diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/include/context.h | 3 | ||||
-rw-r--r-- | source4/include/local.h | 4 | ||||
-rw-r--r-- | source4/librpc/idl/echo.idl | 5 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.c | 43 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_server.h | 1 | ||||
-rw-r--r-- | source4/rpc_server/dcerpc_tcp.c | 189 | ||||
-rw-r--r-- | source4/rpc_server/echo/rpc_echo.c | 2 | ||||
-rw-r--r-- | source4/rpc_server/epmapper/rpc_epmapper.c | 6 | ||||
-rw-r--r-- | source4/smbd/process_single.c | 7 | ||||
-rw-r--r-- | source4/smbd/process_standard.c | 9 | ||||
-rw-r--r-- | source4/smbd/process_thread.c | 10 | ||||
-rw-r--r-- | source4/torture/torture.c | 2 |
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 */ |