summaryrefslogtreecommitdiff
path: root/source4/rpc_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/rpc_server')
-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
5 files changed, 156 insertions, 85 deletions
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"));
}
}