summaryrefslogtreecommitdiff
path: root/source4/rpc_server
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-12-13 23:25:15 +0000
committerAndrew Tridgell <tridge@samba.org>2003-12-13 23:25:15 +0000
commitd262b8c3c79b2fbb0bf8c330d765f89210948a26 (patch)
tree0492a6fa66101b94f5dc368480c2ab027e4f8b77 /source4/rpc_server
parent8d79eb52f104d023122de3965592b4ea36adbb2b (diff)
downloadsamba-d262b8c3c79b2fbb0bf8c330d765f89210948a26.tar.gz
samba-d262b8c3c79b2fbb0bf8c330d765f89210948a26.tar.bz2
samba-d262b8c3c79b2fbb0bf8c330d765f89210948a26.zip
completed the linkage between the endpoint mapper and the dcerpc
server endpoints. We can now successfully setup listening endpoints on high ports, then use our endpoint mapper redirect incoming clients to the right port. also greatly cleanup the rpc over tcp session handling. (This used to be commit 593bc29bbe0e46d356d001160e8a3332a88f2fa8)
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"));
}
}