summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/context.h3
-rw-r--r--source4/include/local.h4
-rw-r--r--source4/librpc/idl/echo.idl5
-rw-r--r--source4/rpc_server/dcerpc_server.c43
-rw-r--r--source4/rpc_server/dcerpc_server.h1
-rw-r--r--source4/rpc_server/dcerpc_tcp.c189
-rw-r--r--source4/rpc_server/echo/rpc_echo.c2
-rw-r--r--source4/rpc_server/epmapper/rpc_epmapper.c6
-rw-r--r--source4/smbd/process_single.c7
-rw-r--r--source4/smbd/process_standard.c9
-rw-r--r--source4/smbd/process_thread.c10
-rw-r--r--source4/torture/torture.c2
12 files changed, 193 insertions, 88 deletions
diff --git a/source4/include/context.h b/source4/include/context.h
index 9ec5d2d8dd..4cfe6c302b 100644
--- a/source4/include/context.h
+++ b/source4/include/context.h
@@ -341,6 +341,9 @@ struct model_ops {
/* function to terminate a connection */
void (*terminate_connection)(struct server_context *smb, const char *reason);
+
+ /* function to terminate a connection */
+ void (*terminate_rpc_connection)(void *r, const char *reason);
/* function to exit server */
void (*exit_server)(struct server_context *smb, const char *reason);
diff --git a/source4/include/local.h b/source4/include/local.h
index 57aac01ca8..81dd7e8b20 100644
--- a/source4/include/local.h
+++ b/source4/include/local.h
@@ -227,4 +227,8 @@
/* size of listen() backlog in smbd */
#define SMBD_LISTEN_BACKLOG 10
+/* the range of ports to try for decrpc over tcp endpoints */
+#define DCERPC_TCP_LOW_PORT 1024
+#define DCERPC_TCP_HIGH_PORT 1300
+
#endif
diff --git a/source4/librpc/idl/echo.idl b/source4/librpc/idl/echo.idl
index e6d93e52c4..d747a39f23 100644
--- a/source4/librpc/idl/echo.idl
+++ b/source4/librpc/idl/echo.idl
@@ -2,8 +2,9 @@
[
-uuid(60a15ec5-4de8-11d7-a637-005056a20182),
-version(1.0)
+ uuid(60a15ec5-4de8-11d7-a637-005056a20182),
+ endpoints(rpcecho, TCP-0),
+ version(1.0)
]
interface rpcecho
{
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index bde7063dcc..4493ffdaa5 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -55,15 +55,44 @@ static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_state *dce, uint
register an endpoint server
*/
BOOL dcesrv_endpoint_register(struct dcesrv_context *dce,
- const struct dcesrv_endpoint_ops *ops)
+ const struct dcesrv_endpoint_ops *ops,
+ const struct dcerpc_interface_table *table)
{
- struct dce_endpoint *ep;
- ep = malloc(sizeof(*ep));
- if (!ep) {
- return False;
+ BOOL done_smb=False;
+ BOOL done_tcp=False;
+ int i;
+
+ for (i=0;i<table->endpoints->count;i++) {
+ struct dce_endpoint *ep;
+ BOOL tcp;
+
+ tcp = (strncasecmp(table->endpoints->names[i], "TCP-", 4) == 0);
+
+ if (tcp) {
+ if (done_tcp) continue;
+ done_tcp = True;
+ } else {
+ if (done_smb) continue;
+ done_smb = True;
+ }
+
+ ep = malloc(sizeof(*ep));
+ if (!ep) {
+ return False;
+ }
+
+ if (tcp) {
+ ep->endpoint.type = ENDPOINT_TCP;
+ ep->endpoint.info.tcp_port = atoi(table->endpoints->names[i]+4);
+ } else {
+ ep->endpoint.type = ENDPOINT_SMB;
+ ep->endpoint.info.smb_pipe = table->endpoints->names[i];
+ }
+
+ ep->endpoint_ops = ops;
+ DLIST_ADD(dce->endpoint_list, ep);
}
- ep->endpoint_ops = ops;
- DLIST_ADD(dce->endpoint_list, ep);
+
return True;
}
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index b7206163f4..dbc24722ce 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -135,6 +135,7 @@ struct dcesrv_context {
/* the list of endpoints servers that have registered */
struct dce_endpoint {
struct dce_endpoint *next, *prev;
+ struct dcesrv_endpoint endpoint;
const struct dcesrv_endpoint_ops *endpoint_ops;
} *endpoint_list;
};
diff --git a/source4/rpc_server/dcerpc_tcp.c b/source4/rpc_server/dcerpc_tcp.c
index 1f8230eb1c..8ea0605fb7 100644
--- a/source4/rpc_server/dcerpc_tcp.c
+++ b/source4/rpc_server/dcerpc_tcp.c
@@ -22,11 +22,36 @@
#include "includes.h"
-struct rpc_listen {
- struct dce_endpoint *e;
- struct model_ops *model_ops;
+struct rpc_server_context {
+ struct dcesrv_endpoint *endpoint;
+ const struct dcesrv_endpoint_ops *endpoint_ops;
+ const struct model_ops *model_ops;
+ struct dcesrv_state *dce;
+ struct dcesrv_context dcesrv_context;
+ int socket_fd;
+ struct event_context *events;
};
+/*
+ a callback from the process model termination routine
+*/
+void rpc_server_terminate(void *rr)
+{
+ struct rpc_server_context *r = rr;
+
+ dcesrv_endpoint_disconnect(r->dce);
+ close(r->socket_fd);
+ event_remove_fd_all(r->events, r->socket_fd);
+ free(r);
+}
+
+/*
+ called when a rpc session needs to be shutdown
+*/
+static void terminate_rpc_session(struct rpc_server_context *r, const char *reason)
+{
+ r->model_ops->terminate_rpc_connection(r, reason);
+}
/*
called when a RPC socket becomes writable
@@ -34,22 +59,26 @@ struct rpc_listen {
static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde,
time_t t, uint16 flags)
{
- struct dcesrv_state *dce = fde->private;
+ struct rpc_server_context *r = fde->private;
DATA_BLOB blob;
NTSTATUS status;
- blob = data_blob(NULL, 3);
+ blob = data_blob(NULL, 0x4000);
if (!blob.data) {
- smb_panic("out of memory in rpc write handler");
+ terminate_rpc_session(r, "out of memory");
+ return;
}
- status = dcesrv_output(dce, &blob);
- if (!NT_STATUS_IS_OK(status)) {
- fde->flags &= ~EVENT_FD_WRITE;
- } else {
+ status = dcesrv_output(r->dce, &blob);
+
+ if (NT_STATUS_IS_OK(status)) {
write_data(fde->fd, blob.data, blob.length);
}
+ if (!r->dce->call_list || !r->dce->call_list->replies) {
+ fde->flags &= ~EVENT_FD_WRITE;
+ }
+
data_blob_free(&blob);
}
@@ -59,31 +88,32 @@ static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde,
static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
time_t t, uint16 flags)
{
- struct dcesrv_state *dce = fde->private;
+ struct rpc_server_context *r = fde->private;
DATA_BLOB blob;
ssize_t ret;
- blob = data_blob(NULL, 3);
+ blob = data_blob(NULL, 0x4000);
if (!blob.data) {
- smb_panic("out of memory in rpc read handler");
+ terminate_rpc_session(r, "out of memory");
+ return;
}
ret = read(fde->fd, blob.data, blob.length);
- if (ret == 0) {
- smb_panic("need a shutdown routine");
- }
- if (ret == -1 && errno != EINTR) {
- smb_panic("need a shutdown routine");
+ if (ret == 0 || (ret == -1 && errno != EINTR)) {
+ terminate_rpc_session(r, "eof on socket");
+ return;
}
if (ret == -1) {
return;
}
- dcesrv_input(dce, &blob);
+ dcesrv_input(r->dce, &blob);
data_blob_free(&blob);
- fde->flags |= EVENT_FD_WRITE;
+ if (r->dce->call_list && r->dce->call_list->replies) {
+ fde->flags |= EVENT_FD_WRITE;
+ }
}
@@ -93,7 +123,7 @@ static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
called when a RPC socket becomes readable
*/
static void dcerpc_io_handler(struct event_context *ev, struct fd_event *fde,
- time_t t, uint16 flags)
+ time_t t, uint16 flags)
{
if (flags & EVENT_FD_WRITE) {
dcerpc_write_handler(ev, fde, t, flags);
@@ -110,25 +140,20 @@ static void dcerpc_io_handler(struct event_context *ev, struct fd_event *fde,
*/
void init_rpc_session(struct event_context *ev, void *private, int fd)
{
- struct dcesrv_context context;
- struct dcesrv_state *dce;
struct fd_event fde;
- struct rpc_listen *r = private;
- struct dcesrv_endpoint endpoint;
+ struct rpc_server_context *r = private;
- set_socket_options(fd,"SO_KEEPALIVE");
- set_socket_options(fd, lp_socket_options());
+ r = memdup(r, sizeof(struct rpc_server_context));
- context.endpoint_list = NULL;
- dcesrv_init(&context);
+ r->events = ev;
+ r->socket_fd = fd;
- endpoint.type = ENDPOINT_TCP;
- endpoint.info.tcp_port = 0;
+ set_socket_options(fd,"SO_KEEPALIVE");
+ set_socket_options(fd, lp_socket_options());
- dcesrv_endpoint_connect_ops(&context, &endpoint, r->e->endpoint_ops, &dce);
+ dcesrv_endpoint_connect_ops(&r->dcesrv_context, r->endpoint, r->endpoint_ops, &r->dce);
- dce->dce = talloc_p(dce->mem_ctx, struct dcesrv_context);
- *dce->dce = context;
+ r->dce->dce = &r->dcesrv_context;
set_blocking(fd, False);
@@ -136,7 +161,7 @@ void init_rpc_session(struct event_context *ev, void *private, int fd)
only interested in reading from the socket */
fde.fd = fd;
fde.handler = dcerpc_io_handler;
- fde.private = dce;
+ fde.private = r;
fde.flags = EVENT_FD_READ;
event_add_fd(ev, &fde);
@@ -148,38 +173,58 @@ void init_rpc_session(struct event_context *ev, void *private, int fd)
*/
static void setup_listen_rpc(struct event_context *events,
struct model_ops *model_ops,
- struct in_addr *ifip, unsigned port,
- struct dce_endpoint *e)
+ struct in_addr *ifip, uint32 *port,
+ struct rpc_server_context *r,
+ const struct dcesrv_endpoint_ops *endpoint_ops)
{
struct fd_event fde;
- struct rpc_listen *r;
+ int i;
+
+ if (*port == 0) {
+ fde.fd = -1;
+ for (i=DCERPC_TCP_LOW_PORT;i<= DCERPC_TCP_HIGH_PORT;i++) {
+ fde.fd = open_socket_in(SOCK_STREAM, i, 0, ifip->s_addr, True);
+ if (fde.fd != -1) break;
+ }
+ if (fde.fd != -1) {
+ *port = i;
+ }
+ } else {
+ fde.fd = open_socket_in(SOCK_STREAM, *port, 0, ifip->s_addr, True);
+ }
- fde.fd = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
if (fde.fd == -1) {
DEBUG(0,("Failed to open socket on %s:%u - %s\n",
- inet_ntoa(*ifip), port, strerror(errno)));
+ inet_ntoa(*ifip), *port, strerror(errno)));
return;
}
+ /* each listening socket has separate state, so must use a different context */
+ r = memdup(r, sizeof(struct rpc_server_context));
+ if (!r) {
+ smb_panic("out of memory");
+ }
+
+ r->endpoint_ops = endpoint_ops;
+
+ r->endpoint = malloc(sizeof(struct dcesrv_endpoint));
+ if (!r->endpoint) {
+ smb_panic("out of memory");
+ }
+ r->endpoint->type = ENDPOINT_TCP;
+ r->endpoint->info.tcp_port = *port;
+
/* ready to listen */
set_socket_options(fde.fd, "SO_KEEPALIVE");
set_socket_options(fde.fd, lp_socket_options());
if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) {
DEBUG(0,("Failed to listen on %s:%d - %s\n",
- inet_ntoa(*ifip), port, strerror(errno)));
+ inet_ntoa(*ifip), *port, strerror(errno)));
close(fde.fd);
return;
}
- r = malloc(sizeof(*r));
- if (!r) {
- return;
- }
-
- r->e = e;
- r->model_ops = model_ops;
-
/* we are only interested in read events on the listen socket */
fde.flags = EVENT_FD_READ;
fde.private = r;
@@ -195,37 +240,29 @@ static void add_socket_rpc(struct event_context *events,
struct model_ops *model_ops,
struct in_addr *ifip)
{
- struct dcesrv_context dce;
- TALLOC_CTX *mem_ctx;
-
- mem_ctx = talloc_init("add_socket_rpc");
- if (!mem_ctx) {
- smb_panic("out of memory in add_socket_rpc");
+ struct dce_endpoint *e;
+ struct rpc_server_context *r;
+
+ r = malloc(sizeof(struct rpc_server_context));
+ if (!r) {
+ smb_panic("out of memory");
}
+
+ r->dcesrv_context.endpoint_list = NULL;
+ dcesrv_init(&r->dcesrv_context);
+ r->endpoint = NULL;
+ r->model_ops = model_ops;
+ r->dce = NULL;
+ r->socket_fd = -1;
+ r->events = NULL;
- dce.endpoint_list = NULL;
-
- dcesrv_init(&dce);
-
- while (dce.endpoint_list) {
- struct dce_endpoint *e = dce.endpoint_list;
- struct dcesrv_ep_iface *ifaces;
- int count, i;
-
- count = e->endpoint_ops->lookup_endpoints(mem_ctx, &ifaces);
- for (i=0;i<count;i++) {
- if (ifaces[i].endpoint.type == ENDPOINT_TCP) {
- setup_listen_rpc(events, model_ops, ifip,
- ifaces[i].endpoint.info.tcp_port,
- e);
- break;
- }
+ for (e=r->dcesrv_context.endpoint_list;e;e=e->next) {
+ if (e->endpoint.type == ENDPOINT_TCP) {
+ setup_listen_rpc(events, model_ops, ifip,
+ &e->endpoint.info.tcp_port,
+ r, e->endpoint_ops);
}
-
- DLIST_REMOVE(dce.endpoint_list, e);
}
-
- talloc_destroy(mem_ctx);
}
/****************************************************************************
diff --git a/source4/rpc_server/echo/rpc_echo.c b/source4/rpc_server/echo/rpc_echo.c
index 0f3c504c37..d62ebc3d26 100644
--- a/source4/rpc_server/echo/rpc_echo.c
+++ b/source4/rpc_server/echo/rpc_echo.c
@@ -181,7 +181,7 @@ static const struct dcesrv_endpoint_ops rpc_echo_ops = {
*/
void rpc_echo_init(struct dcesrv_context *dce)
{
- if (!dcesrv_endpoint_register(dce, &rpc_echo_ops)) {
+ if (!dcesrv_endpoint_register(dce, &rpc_echo_ops, &dcerpc_table_rpcecho)) {
DEBUG(1,("Failed to register rpcecho endpoint\n"));
}
}
diff --git a/source4/rpc_server/epmapper/rpc_epmapper.c b/source4/rpc_server/epmapper/rpc_epmapper.c
index 32a239f44d..43e4d4514f 100644
--- a/source4/rpc_server/epmapper/rpc_epmapper.c
+++ b/source4/rpc_server/epmapper/rpc_epmapper.c
@@ -118,6 +118,10 @@ static uint32 build_ep_list(TALLOC_CTX *mem_ctx,
struct dcesrv_ep_iface *e;
int count = d->endpoint_ops->lookup_endpoints(mem_ctx, &e);
if (count > 0) {
+ int i;
+ for (i=0;i<count;i++) {
+ e[i].endpoint = d->endpoint;
+ }
(*eps) = talloc_realloc_p(mem_ctx, *eps,
struct dcesrv_ep_iface,
total + count);
@@ -387,7 +391,7 @@ static const struct dcesrv_endpoint_ops rpc_epmapper_ops = {
*/
void rpc_epmapper_init(struct dcesrv_context *dce)
{
- if (!dcesrv_endpoint_register(dce, &rpc_epmapper_ops)) {
+ if (!dcesrv_endpoint_register(dce, &rpc_epmapper_ops, &dcerpc_table_epmapper)) {
DEBUG(1,("Failed to register epmapper endpoint\n"));
}
}
diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c
index a19577b3cf..8f1362bed3 100644
--- a/source4/smbd/process_single.c
+++ b/source4/smbd/process_single.c
@@ -81,6 +81,12 @@ static void terminate_connection(struct server_context *server, const char *reas
server_terminate(server);
}
+/* called when a rpc connection goes down */
+static void terminate_rpc_connection(void *r, const char *reason)
+{
+ rpc_server_terminate(r);
+}
+
static int get_id(struct request_context *req)
{
return (int)req->smb->pid;
@@ -100,6 +106,7 @@ void process_model_single_init(void)
ops.accept_connection = accept_connection;
ops.accept_rpc_connection = accept_rpc_connection;
ops.terminate_connection = terminate_connection;
+ ops.terminate_rpc_connection = terminate_rpc_connection;
ops.exit_server = NULL;
ops.get_id = get_id;
diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c
index 507c179a26..505c2aafbf 100644
--- a/source4/smbd/process_standard.c
+++ b/source4/smbd/process_standard.c
@@ -121,6 +121,14 @@ static void terminate_connection(struct server_context *server, const char *reas
exit(0);
}
+/* called when a rpc connection goes down */
+static void terminate_rpc_connection(void *r, const char *reason)
+{
+ rpc_server_terminate(r);
+ /* terminate this process */
+ exit(0);
+}
+
static int get_id(struct request_context *req)
{
return (int)req->smb->pid;
@@ -140,6 +148,7 @@ void process_model_standard_init(void)
ops.accept_connection = accept_connection;
ops.accept_rpc_connection = accept_rpc_connection;
ops.terminate_connection = terminate_connection;
+ ops.terminate_rpc_connection = terminate_rpc_connection;
ops.get_id = get_id;
/* register ourselves with the process model subsystem. We register under the name 'standard'. */
diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c
index 634e826395..d02238c840 100644
--- a/source4/smbd/process_thread.c
+++ b/source4/smbd/process_thread.c
@@ -134,6 +134,15 @@ static void terminate_connection(struct server_context *server, const char *reas
pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
}
+/* called when a rpc connection goes down */
+static void terminate_rpc_connection(void *r, const char *reason)
+{
+ rpc_server_terminate(r);
+
+ /* terminate this thread */
+ pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */
+}
+
/*
mutex init function for thread model
*/
@@ -457,6 +466,7 @@ void process_model_thread_init(void)
ops.accept_connection = accept_connection;
ops.accept_rpc_connection = accept_rpc_connection;
ops.terminate_connection = terminate_connection;
+ ops.terminate_rpc_connection = terminate_rpc_connection;
ops.exit_server = NULL;
ops.get_id = get_id;
diff --git a/source4/torture/torture.c b/source4/torture/torture.c
index cc0a83fe80..76d1e82a0f 100644
--- a/source4/torture/torture.c
+++ b/source4/torture/torture.c
@@ -165,7 +165,7 @@ static NTSTATUS torture_rpc_tcp(struct dcerpc_pipe **p,
/* always do NDR validation in smbtorture */
(*p)->flags |= DCERPC_DEBUG_VALIDATE_BOTH;
-#if 0
+#if 1
status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
#else
/* enable signing on tcp connections */