completed the linkage between the endpoint mapper and the dcerpc
authorAndrew Tridgell <tridge@samba.org>
Sat, 13 Dec 2003 23:25:15 +0000 (23:25 +0000)
committerAndrew Tridgell <tridge@samba.org>
Sat, 13 Dec 2003 23:25:15 +0000 (23:25 +0000)
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)

12 files changed:
source4/include/context.h
source4/include/local.h
source4/librpc/idl/echo.idl
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h
source4/rpc_server/dcerpc_tcp.c
source4/rpc_server/echo/rpc_echo.c
source4/rpc_server/epmapper/rpc_epmapper.c
source4/smbd/process_single.c
source4/smbd/process_standard.c
source4/smbd/process_thread.c
source4/torture/torture.c

index 9ec5d2d8dd2e1505ba65ebdbf13bc56a33d7b677..4cfe6c302b81aa35a270db8b30578ce9f2a5a5b3 100644 (file)
@@ -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);
index 57aac01ca8016daaeecc45445340994bd0e1fb8f..81dd7e8b203b0e31084b524648949c53fa0e9321 100644 (file)
 /* 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
index e6d93e52c425afe3e2ae58222f9bbe3612d87415..d747a39f23a0c9a46a69cb5c41f87b96ef74ff1d 100644 (file)
@@ -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
 {
index bde7063dcc596a132134c5c3faa2e4415ea58881..4493ffdaa5e3446336318dff227cd0db1d89c88d 100644 (file)
@@ -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;
 }
 
index b7206163f43c5f246a34df5e1765a9bc13dabe4b..dbc24722ce07c88da3b9774cd33f9891b6fb29a8 100644 (file)
@@ -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;
 };
index 1f8230eb1c5f545bb0c702af9bb726de92f0e3a2..8ea0605fb7d5966434f46da82ac3629362e2c568 100644 (file)
 
 #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);
 }
 
 /****************************************************************************
index 0f3c504c37cb622e08679b4967d92dff1a7018d3..d62ebc3d26014de7a82f4f04fc6c3501d5e6de72 100644 (file)
@@ -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"));
        }
 }
index 32a239f44df76edb1733cf0ce2d194927dbf9161..43e4d4514f8b2c9d5d0b18f7f5df719d28f86bdc 100644 (file)
@@ -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"));
        }
 }
index a19577b3cf470d77a4a0338d2276acbf13b766ed..8f1362bed3d0ec007be5cf9e3faf97c192334750 100644 (file)
@@ -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;
 
index 507c179a26dab185ae1ed143bc986ba65ddbf869..505c2aafbf7cf764397313014c1021ffd56b9e9b 100644 (file)
@@ -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'. */
index 634e826395f9076c317e236a88851d00272458a6..d02238c840b3cf32a27b150ff17fb16339ed04db 100644 (file)
@@ -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;
        
index cc0a83fe80b79925c157f6b845867355943a2437..76d1e82a0ff90dfdae46d0cb0ac534dc5b595009 100644 (file)
@@ -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 */