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.c105
-rw-r--r--source4/rpc_server/dcerpc_server.h4
-rw-r--r--source4/rpc_server/dcerpc_tcp.c350
3 files changed, 242 insertions, 217 deletions
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index e5c4c120a5..34756349c6 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -271,6 +271,7 @@ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
(*p)->auth_state.auth_info = NULL;
(*p)->auth_state.gensec_security = NULL;
(*p)->auth_state.session_info = NULL;
+ (*p)->srv_conn = NULL;
return NT_STATUS_OK;
}
@@ -1016,6 +1017,87 @@ NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx)
return NT_STATUS_OK;
}
+static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops)
+{
+ TALLOC_CTX *mem_ctx;
+ struct dcesrv_context *dce_ctx;
+ int i;
+ const char **endpoint_servers = lp_dcerpc_endpoint_servers();
+
+ DEBUG(0,("dcesrv_init\n"));
+
+
+ if (!endpoint_servers) {
+ DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n"));
+ return;
+ }
+
+ mem_ctx = talloc_init("struct dcesrv_context");
+
+ dce_ctx = talloc_p(mem_ctx, struct dcesrv_context);
+ if (!dce_ctx) {
+ DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n"));
+ return;
+ }
+
+ ZERO_STRUCTP(dce_ctx);
+ dce_ctx->mem_ctx = mem_ctx;
+ dce_ctx->endpoint_list = NULL;
+
+ for (i=0;endpoint_servers[i];i++) {
+ NTSTATUS ret;
+ const struct dcesrv_endpoint_server *ep_server;
+
+ ep_server = dcesrv_ep_server_byname(endpoint_servers[i]);
+ if (!ep_server) {
+ DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i]));
+ return;
+ }
+
+ ret = ep_server->init_server(dce_ctx, ep_server);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i]));
+ return;
+ }
+ }
+
+ dcesrv_tcp_init(service, model_ops, dce_ctx);
+
+ return;
+}
+
+static void dcesrv_accept(struct server_connection *srv_conn)
+{
+ dcesrv_tcp_accept(srv_conn);
+}
+
+static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags)
+{
+ dcesrv_tcp_recv(srv_conn, t, flags);
+}
+
+static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags)
+{
+ dcesrv_tcp_send(srv_conn, t, flags);
+}
+
+static void dcesrv_idle(struct server_connection *srv_conn, time_t t)
+{
+ dcesrv_tcp_idle(srv_conn, t);
+}
+
+static void dcesrv_close(struct server_connection *srv_conn, const char *reason)
+{
+ dcesrv_tcp_close(srv_conn, reason);
+ return;
+}
+
+static void dcesrv_exit(struct server_service *service, const char *reason)
+{
+ dcesrv_tcp_exit(service, reason);
+ return;
+}
+
/* the list of currently registered DCERPC endpoint servers.
*/
static struct {
@@ -1101,7 +1183,7 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void)
/*
initialise the DCERPC subsystem
*/
-BOOL dcesrv_init(void)
+BOOL subsystem_dcerpc_init(void)
{
NTSTATUS status;
@@ -1116,3 +1198,24 @@ BOOL dcesrv_init(void)
DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION));
return True;
}
+
+static const struct server_service_ops dcesrv_ops = {
+ .name = "rpc",
+ .service_init = dcesrv_init,
+ .accept_connection = dcesrv_accept,
+ .recv_handler = dcesrv_recv,
+ .send_handler = dcesrv_send,
+ .idle_handler = dcesrv_idle,
+ .close_connection = dcesrv_close,
+ .service_exit = dcesrv_exit,
+};
+
+const struct server_service_ops *dcesrv_get_ops(void)
+{
+ return &dcesrv_ops;
+}
+
+NTSTATUS server_service_rpc_init(void)
+{
+ return NT_STATUS_OK;
+}
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index b1754dd4a3..15da3e38bb 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -39,7 +39,7 @@ struct dcesrv_ep_description {
enum endpoint_type type;
union {
const char *smb_pipe;
- uint32_t tcp_port;
+ uint16_t tcp_port;
} info;
};
@@ -132,6 +132,8 @@ struct dcesrv_connection {
/* the current authentication state */
struct dcesrv_auth auth_state;
+
+ struct server_connection *srv_conn;
};
diff --git a/source4/rpc_server/dcerpc_tcp.c b/source4/rpc_server/dcerpc_tcp.c
index 83a9140dd1..c506cf16cf 100644
--- a/source4/rpc_server/dcerpc_tcp.c
+++ b/source4/rpc_server/dcerpc_tcp.c
@@ -23,39 +23,12 @@
#include "includes.h"
-struct rpc_server_context {
- struct dcesrv_ep_description *ep_description;
+struct dcesrv_socket_context {
const struct dcesrv_endpoint *endpoint;
- const struct model_ops *model_ops;
- struct dcesrv_connection *dce_conn;
- struct dcesrv_context dcesrv_context;
- int socket_fd;
- struct event_context *events;
+ struct dcesrv_context *dcesrv_ctx;
};
/*
- 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_conn);
- 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);
-}
-
-
-/*
write_fn callback for dcesrv_output()
*/
static ssize_t dcerpc_write_fn(void *private, const void *buf, size_t count)
@@ -69,45 +42,128 @@ static ssize_t dcerpc_write_fn(void *private, const void *buf, size_t count)
return ret;
}
+void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason)
+{
+ server_terminate_connection(dce_conn->srv_conn, reason);
+}
+
/*
- called when a RPC socket becomes writable
+ add a socket address to the list of events, one event per dcerpc endpoint
*/
-static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde,
- time_t t, uint16_t flags)
+static void add_socket_rpc(struct server_service *service,
+ const struct model_ops *model_ops,
+ struct socket_context *socket_ctx,
+ struct dcesrv_context *dce_ctx,
+ struct in_addr *ifip)
{
- struct rpc_server_context *r = fde->private;
- NTSTATUS status;
+ struct dcesrv_endpoint *e;
- status = dcesrv_output(r->dce_conn, fde, dcerpc_write_fn);
- if (NT_STATUS_IS_ERR(status)) {
- /* TODO: destroy fd_event? */
+ for (e=dce_ctx->endpoint_list;e;e=e->next) {
+ if (e->ep_description.type == ENDPOINT_TCP) {
+ struct server_socket *sock;
+ struct dcesrv_socket_context *dcesrv_sock;
+
+ sock = service_setup_socket(service,model_ops,socket_ctx,ifip, &e->ep_description.info.tcp_port);
+ if (!sock) {
+ DEBUG(0,("service_setup_socket(port=%u) failed\n",e->ep_description.info.tcp_port));
+ continue;
+ }
+
+ dcesrv_sock = talloc_p(sock->mem_ctx, struct dcesrv_socket_context);
+ if (!dcesrv_sock) {
+ DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n"));
+ continue;
+ }
+
+ /* remeber the enpoint of this socket */
+ dcesrv_sock->endpoint = e;
+ dcesrv_sock->dcesrv_ctx = dce_ctx;
+
+ sock->private_data = dcesrv_sock;
+ }
}
+}
- if (!r->dce_conn->call_list || !r->dce_conn->call_list->replies) {
- fde->flags &= ~EVENT_FD_WRITE;
+/****************************************************************************
+ Open the listening sockets for RPC over TCP
+****************************************************************************/
+void dcesrv_tcp_init(struct server_service *service, const struct model_ops *model_ops, struct dcesrv_context *dce_ctx)
+{
+ DEBUG(1,("dcesrv_tcp_init\n"));
+
+ if (lp_interfaces() && lp_bind_interfaces_only()) {
+ int num_interfaces = iface_count();
+ int i;
+ for(i = 0; i < num_interfaces; i++) {
+ struct in_addr *ifip = iface_n_ip(i);
+ if (ifip == NULL) {
+ continue;
+ }
+ add_socket_rpc(service, model_ops, NULL, dce_ctx, ifip);
+ }
+ } else {
+ struct in_addr *ifip;
+ TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");
+ if (!mem_ctx) {
+ smb_panic("No memory");
+ }
+
+ ifip = interpret_addr2(mem_ctx, lp_socket_address());
+ add_socket_rpc(service, model_ops, NULL, dce_ctx, ifip);
+ talloc_destroy(mem_ctx);
}
+
+ return;
}
-/*
- called when a RPC socket becomes readable
-*/
-static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
- time_t t, uint16_t flags)
+void dcesrv_tcp_accept(struct server_connection *conn)
+{
+ NTSTATUS status;
+ struct dcesrv_socket_context *dcesrv_sock = conn->server_socket->private_data;
+ struct dcesrv_connection *dcesrv_conn = NULL;
+
+ DEBUG(5,("dcesrv_tcp_accept\n"));
+
+
+
+ status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, dcesrv_sock->endpoint, &dcesrv_conn);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("dcesrv_tcp_accept: dcesrv_endpoint_connect failed: %s\n",
+ nt_errstr(status)));
+ return;
+ }
+
+ dcesrv_conn->srv_conn = conn;
+
+ conn->private_data = dcesrv_conn;
+
+ /* TODO: this should to the generic code
+ * but the smb server can't handle it yet
+ * --metze
+ */
+ set_blocking(conn->socket->fde->fd, False);
+
+ return;
+}
+
+void dcesrv_tcp_recv(struct server_connection *conn, time_t t, uint16_t flags)
{
- struct rpc_server_context *r = fde->private;
+ struct dcesrv_connection *dce_conn = conn->private_data;
DATA_BLOB blob;
ssize_t ret;
+ DEBUG(10,("dcesrv_tcp_recv\n"));
+
blob = data_blob(NULL, 0x4000);
if (!blob.data) {
- terminate_rpc_session(r, "out of memory");
+ dcesrv_terminate_connection(dce_conn, "eof on socket");
return;
}
- ret = read(fde->fd, blob.data, blob.length);
+ ret = read(conn->socket->fde->fd, blob.data, blob.length);
if (ret == 0 || (ret == -1 && errno != EINTR)) {
data_blob_free(&blob);
- terminate_rpc_session(r, "eof on socket");
+ dcesrv_terminate_connection(dce_conn, "eof on socket");
return;
}
if (ret == -1) {
@@ -117,197 +173,61 @@ static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde,
blob.length = ret;
- dcesrv_input(r->dce_conn, &blob);
+ dcesrv_input(dce_conn, &blob);
data_blob_free(&blob);
- if (r->dce_conn->call_list && r->dce_conn->call_list->replies) {
- fde->flags |= EVENT_FD_WRITE;
+ if (dce_conn->call_list && dce_conn->call_list->replies) {
+ conn->socket->fde->flags |= EVENT_FD_WRITE;
}
-}
-
-
-
-/*
- called when a RPC socket becomes readable
-*/
-static void dcerpc_io_handler(struct event_context *ev, struct fd_event *fde,
- time_t t, uint16_t flags)
-{
- if (flags & EVENT_FD_WRITE) {
- dcerpc_write_handler(ev, fde, t, flags);
- }
-
- if (flags & EVENT_FD_READ) {
- dcerpc_read_handler(ev, fde, t, flags);
- }
+ return;
}
-
-/*
- initialise a server_context from a open socket and register a event handler
- for reading from that socket
-*/
-void init_rpc_session(struct event_context *ev, void *private, int fd)
+
+void dcesrv_tcp_send(struct server_connection *conn, time_t t, uint16_t flags)
{
- struct fd_event fde;
- struct rpc_server_context *r = private;
+ struct dcesrv_connection *dce_conn = conn->private_data;
NTSTATUS status;
- r = memdup(r, sizeof(struct rpc_server_context));
-
- r->events = ev;
- r->socket_fd = fd;
+ DEBUG(10,("dcesrv_tcp_send\n"));
- set_socket_options(fd,"SO_KEEPALIVE");
- set_socket_options(fd, lp_socket_options());
-
- status = dcesrv_endpoint_connect(&r->dcesrv_context, r->endpoint, &r->dce_conn);
- if (!NT_STATUS_IS_OK(status)) {
- close(fd);
- free(r);
- DEBUG(0,("init_rpc_session: connection to endpoint failed: %s\n",
- nt_errstr(status)));
- return;
+ status = dcesrv_output(dce_conn, conn->socket->fde, dcerpc_write_fn);
+ if (NT_STATUS_IS_ERR(status)) {
+ /* TODO: destroy fd_event? */
}
- r->dce_conn->dce_ctx = &r->dcesrv_context;
-
- set_blocking(fd, False);
-
- /* setup a event handler for this socket. We are initially
- only interested in reading from the socket */
- fde.fd = fd;
- fde.handler = dcerpc_io_handler;
- fde.private = r;
- fde.flags = EVENT_FD_READ;
+ if (!dce_conn->call_list || !dce_conn->call_list->replies) {
+ conn->socket->fde->flags &= ~EVENT_FD_WRITE;
+ }
- event_add_fd(ev, &fde);
+ return;
}
-
-/*
- setup a single rpc listener
- */
-static void setup_listen_rpc(struct event_context *events,
- const struct model_ops *model_ops,
- struct in_addr *ifip, uint32_t *port,
- struct rpc_server_context *r,
- const struct dcesrv_endpoint *endpoint)
+void dcesrv_tcp_idle(struct server_connection *conn, time_t t)
{
- struct fd_event fde;
- 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);
- }
+ DEBUG(10,("dcesrv_tcp_idle\n"));
+ conn->event.idle->next_event = t + 5;
- if (fde.fd == -1) {
- DEBUG(0,("Failed to open socket on %s:%u - %s\n",
- 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->ep_description = malloc(sizeof(struct dcesrv_ep_description));
- if (!r->ep_description) {
- smb_panic("out of memory");
- }
- r->ep_description->type = ENDPOINT_TCP;
- r->ep_description->info.tcp_port = *port;
-
- r->endpoint = endpoint;
-
- /* 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)));
- close(fde.fd);
- return;
- }
-
- /* we are only interested in read events on the listen socket */
- fde.flags = EVENT_FD_READ;
- fde.private = r;
- fde.handler = model_ops->accept_rpc_connection;
-
- event_add_fd(events, &fde);
+ return;
}
-/*
- add a socket address to the list of events, one event per dcerpc endpoint
-*/
-static void add_socket_rpc(struct event_context *events,
- const struct model_ops *model_ops,
- struct in_addr *ifip)
+void dcesrv_tcp_close(struct server_connection *conn, const char *reason)
{
- struct dcesrv_endpoint *e;
- struct rpc_server_context *r;
+ struct dcesrv_connection *dce_conn = conn->private_data;
- r = malloc(sizeof(struct rpc_server_context));
- if (!r) {
- smb_panic("out of memory");
- }
+ DEBUG(5,("dcesrv_tcp_close: %s\n",reason));
- r->dcesrv_context.endpoint_list = NULL;
- dcesrv_init_context(&r->dcesrv_context);
- r->ep_description = NULL;
- r->model_ops = model_ops;
- r->dce_conn = NULL;
- r->socket_fd = -1;
- r->events = NULL;
-
- for (e=r->dcesrv_context.endpoint_list;e;e=e->next) {
- if (e->ep_description.type == ENDPOINT_TCP) {
- setup_listen_rpc(events, model_ops, ifip,
- &e->ep_description.info.tcp_port,
- r, e);
- }
- }
+ close(conn->event.fde->fd);
+ event_remove_fd_all(conn->event.ctx, conn->socket->fde->fd);
+ event_remove_timed(conn->event.ctx, conn->event.idle);
- free(r);
+ talloc_destroy(dce_conn->mem_ctx);
+
+ return;
}
-/****************************************************************************
- Open the listening sockets for RPC over TCP
-****************************************************************************/
-void open_sockets_rpc(struct event_context *events,
- const struct model_ops *model_ops)
+void dcesrv_tcp_exit(struct server_service *service, const char *reason)
{
- if (lp_interfaces() && lp_bind_interfaces_only()) {
- int num_interfaces = iface_count();
- int i;
- for(i = 0; i < num_interfaces; i++) {
- struct in_addr *ifip = iface_n_ip(i);
- if (ifip == NULL) {
- continue;
- }
- add_socket_rpc(events, model_ops, ifip);
- }
- } else {
- TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");
- struct in_addr *ifip = interpret_addr2(mem_ctx, lp_socket_address());
- if (!mem_ctx) {
- smb_panic("No memory");
- }
- add_socket_rpc(events, model_ops, ifip);
- talloc_destroy(mem_ctx);
- }
+ DEBUG(1,("dcesrv_tcp_exit: %s\n",reason));
+ return;
}