diff options
author | Andrew Tridgell <tridge@samba.org> | 2003-12-13 23:25:15 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2003-12-13 23:25:15 +0000 |
commit | d262b8c3c79b2fbb0bf8c330d765f89210948a26 (patch) | |
tree | 0492a6fa66101b94f5dc368480c2ab027e4f8b77 | |
parent | 8d79eb52f104d023122de3965592b4ea36adbb2b (diff) | |
download | samba-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)
-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 */ |