diff options
Diffstat (limited to 'source4/rpc_server/dcerpc_tcp.c')
-rw-r--r-- | source4/rpc_server/dcerpc_tcp.c | 189 |
1 files changed, 113 insertions, 76 deletions
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); } /**************************************************************************** |