rpc_server: Add dcesrv_setup_ncacn_listener()
authorVolker Lendecke <vl@samba.org>
Tue, 12 Jan 2021 15:48:25 +0000 (16:48 +0100)
committerVolker Lendecke <vl@samba.org>
Thu, 14 Jan 2021 13:29:35 +0000 (13:29 +0000)
This is supposed to replace the protocol-specific dcerpc_setup_*
functions. They are all very similar except the way to create the
socket file descriptor. By handing out the anonymous structure
"listen_state" for an error path the listener tevent_fd structs can be
cancelled individually or handed over to other talloc parents.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Samuel Cabrero <scabrero@samba.org>
source3/rpc_server/rpc_server.c
source3/rpc_server/rpc_server.h

index c58d76a947dd8512030e207401c9fd694e2f620c..d676a1d6544932b1ce554e5ebfec7949c23fd23b 100644 (file)
@@ -667,6 +667,142 @@ static void dcesrv_ncalrpc_listener(struct tevent_context *ev,
                            state->termination_data);
 }
 
+static void dcesrv_ncacn_listener(
+       struct tevent_context *ev,
+       struct tevent_fd *fde,
+       uint16_t flags,
+       void *private_data);
+
+int dcesrv_setup_ncacn_listener(
+       TALLOC_CTX *mem_ctx,
+       struct dcesrv_context *dce_ctx,
+       struct tevent_context *ev_ctx,
+       struct messaging_context *msg_ctx,
+       struct dcesrv_endpoint *e,
+       int *fd,
+       dcerpc_ncacn_termination_fn term_fn,
+       void *termination_data,
+       struct dcerpc_ncacn_listen_state **listen_state)
+{
+       struct dcerpc_ncacn_listen_state *state = NULL;
+       struct tevent_fd *fde = NULL;
+       int rc, err = ENOMEM;
+
+       state = talloc_zero(mem_ctx, struct dcerpc_ncacn_listen_state);
+       if (state == NULL) {
+               DBG_ERR("Out of memory\n");
+               return ENOMEM;
+       }
+
+       state->fd = *fd;
+       state->ev_ctx = ev_ctx;
+       state->msg_ctx = msg_ctx;
+       state->dce_ctx = dce_ctx;
+       state->endpoint = e;
+       state->termination_fn = term_fn;
+       state->termination_data = termination_data;
+
+       rc = listen(state->fd, SMBD_LISTEN_BACKLOG);
+       if (rc < 0) {
+               err = errno;
+               DBG_ERR("listen(%d) failed: %s\n",
+                       state->fd,
+                       strerror(err));
+               goto fail;
+       }
+
+       /* Set server socket to non-blocking for the accept. */
+       rc = set_blocking(state->fd, false);
+       if (rc < 0) {
+               err = errno;
+               goto fail;
+       }
+
+       fde = tevent_add_fd(
+               state->ev_ctx,
+               state,
+               state->fd,
+               TEVENT_FD_READ,
+               dcesrv_ncacn_listener,
+               state);
+       if (fde == NULL) {
+               err = errno;
+               DBG_ERR("tevent_add_fd for %d failed: %s\n",
+                       state->fd,
+                       strerror(err));
+               goto fail;
+       }
+       tevent_fd_set_auto_close(fde);
+       *fd = -1;
+
+       *listen_state = state;
+
+       return 0;
+
+fail:
+       TALLOC_FREE(state);
+       return err;
+}
+
+static void dcesrv_ncacn_listener(
+       struct tevent_context *ev,
+       struct tevent_fd *fde,
+       uint16_t flags,
+       void *private_data)
+{
+       struct dcerpc_ncacn_listen_state *state = talloc_get_type_abort(
+               private_data, struct dcerpc_ncacn_listen_state);
+       struct tsocket_address *cli_addr = NULL, *srv_addr = NULL;
+       struct samba_sockaddr addr = {
+               .sa_socklen = sizeof(struct samba_sockaddr),
+       };
+       int sd = -1;
+       int rc;
+
+       sd = accept(state->fd, &addr.u.sa, &addr.sa_socklen);
+       if (sd == -1) {
+               if (errno != EINTR) {
+                       DBG_ERR("Failed to accept: %s\n", strerror(errno));
+               }
+               return;
+       }
+       smb_set_close_on_exec(sd);
+
+       rc = tsocket_address_bsd_from_samba_sockaddr(state, &addr, &cli_addr);
+       if (rc < 0) {
+               goto fail;
+       }
+
+       rc = getsockname(sd, &addr.u.sa, &addr.sa_socklen);
+       if (rc < 0) {
+               goto fail;
+       }
+
+       rc = tsocket_address_bsd_from_samba_sockaddr(state, &addr, &srv_addr);
+       if (rc < 0) {
+               goto fail;
+       }
+
+       dcerpc_ncacn_accept(
+               state->ev_ctx,
+               state->msg_ctx,
+               state->dce_ctx,
+               state->endpoint,
+               &cli_addr,
+               &srv_addr,
+               sd,
+               state->termination_fn,
+               state->termination_data);
+       return;
+
+fail:
+       TALLOC_FREE(cli_addr);
+       TALLOC_FREE(srv_addr);
+       if (sd != -1) {
+               close(sd);
+       }
+}
+
 static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
 {
        struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
index 4a716b9bed5e7dd24c863cf756afd831d64c9ff5..3c47c8fc23496517f8968363a06fe632a0edf0ed 100644 (file)
@@ -93,6 +93,17 @@ NTSTATUS dcesrv_setup_ncalrpc_socket(struct tevent_context *ev_ctx,
                                     struct dcesrv_endpoint *e,
                                     dcerpc_ncacn_termination_fn term_fn,
                                     void *termination_data);
+struct dcerpc_ncacn_listen_state;
+int dcesrv_setup_ncacn_listener(
+       TALLOC_CTX *mem_ctx,
+       struct dcesrv_context *dce_ctx,
+       struct tevent_context *ev_ctx,
+       struct messaging_context *msg_ctx,
+       struct dcesrv_endpoint *e,
+       int *fd,
+       dcerpc_ncacn_termination_fn term_fn,
+       void *termination_data,
+       struct dcerpc_ncacn_listen_state **listen_state);
 
 void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
                         struct messaging_context *msg_ctx,