*/
#include "includes.h"
+#include "librpc/rpc/dcesrv_core.h"
#include "rpc_server/rpc_pipes.h"
#include "rpc_server/rpc_server.h"
#include "rpc_server/rpc_config.h"
#include "auth.h"
#include "rpc_server/rpc_ncacn_np.h"
#include "rpc_server/srv_pipe_hnd.h"
-#include "rpc_server/srv_pipe.h"
+#include "lib/util/idtree_random.h"
-/* Creates a pipes_struct and initializes it with the information
- * sent from the client */
-int make_server_pipes_struct(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg_ctx,
- const char *pipe_name,
- enum dcerpc_transport_t transport,
- const struct tsocket_address *remote_address,
- const struct tsocket_address *local_address,
- struct auth_session_info *session_info,
- struct pipes_struct **_p,
- int *perrno)
-{
- struct pipes_struct *p;
- int ret;
-
- ret = make_base_pipes_struct(mem_ctx, msg_ctx, pipe_name,
- transport, RPC_LITTLE_ENDIAN,
- remote_address, local_address, &p);
- if (ret) {
- *perrno = ret;
- return -1;
- }
-
- if (session_info->unix_token && session_info->unix_info && session_info->security_token) {
- /* Don't call create_local_token(), we already have the full details here */
- p->session_info = talloc_steal(p, session_info);
-
- } else {
- DEBUG(0, ("Supplied session_info in make_server_pipes_struct was incomplete!"));
- *perrno = EINVAL;
- return -1;
- }
-
- *_p = p;
- return 0;
-}
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_RPC_SRV
/* Start listening on the appropriate unix socket and setup all is needed to
* dispatch requests to the pipes rpc implementation */
struct dcerpc_ncacn_listen_state {
- struct ndr_syntax_id syntax_id;
-
int fd;
- union {
- char *name;
- uint16_t port;
- } ep;
struct tevent_context *ev_ctx;
struct messaging_context *msg_ctx;
- dcerpc_ncacn_disconnect_fn disconnect_fn;
+ struct dcesrv_context *dce_ctx;
+ struct dcesrv_endpoint *endpoint;
+ dcerpc_ncacn_termination_fn termination_fn;
+ void *termination_data;
};
-static void named_pipe_listener(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data);
-
-int create_named_pipe_socket(const char *pipe_name)
-{
- char *np_dir = NULL;
- int fd = -1;
-
- /*
- * As lp_ncalrpc_dir() should have 0755, but
- * lp_ncalrpc_dir()/np should have 0700, we need to
- * create lp_ncalrpc_dir() first.
- */
- if (!directory_create_or_exist(lp_ncalrpc_dir(), 0755)) {
- DEBUG(0, ("Failed to create pipe directory %s - %s\n",
- lp_ncalrpc_dir(), strerror(errno)));
- goto out;
- }
-
- np_dir = talloc_asprintf(talloc_tos(), "%s/np", lp_ncalrpc_dir());
- if (!np_dir) {
- DEBUG(0, ("Out of memory\n"));
- goto out;
- }
-
- if (!directory_create_or_exist_strict(np_dir, geteuid(), 0700)) {
- DEBUG(0, ("Failed to create pipe directory %s - %s\n",
- np_dir, strerror(errno)));
- goto out;
- }
-
- fd = create_pipe_sock(np_dir, pipe_name, 0700);
- if (fd == -1) {
- DEBUG(0, ("Failed to create pipe socket! [%s/%s]\n",
- np_dir, pipe_name));
- goto out;
- }
-
- DEBUG(10, ("Opened pipe socket fd %d for %s\n", fd, pipe_name));
-
-out:
- talloc_free(np_dir);
- return fd;
-}
+static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
+ const char *reason);
-bool setup_named_pipe_socket(const char *pipe_name,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
+NTSTATUS dcesrv_auth_gensec_prepare(
+ TALLOC_CTX *mem_ctx,
+ struct dcesrv_call_state *call,
+ struct gensec_security **out,
+ void *private_data)
{
- struct dcerpc_ncacn_listen_state *state;
- struct tevent_fd *fde;
- int rc;
-
- state = talloc(ev_ctx, struct dcerpc_ncacn_listen_state);
- if (!state) {
- DEBUG(0, ("Out of memory\n"));
- return false;
- }
- state->ep.name = talloc_strdup(state, pipe_name);
- if (state->ep.name == NULL) {
- DEBUG(0, ("Out of memory\n"));
- goto out;
- }
- state->fd = create_named_pipe_socket(pipe_name);
- if (state->fd == -1) {
- goto out;
- }
-
- rc = listen(state->fd, 5);
- if (rc < 0) {
- DEBUG(0, ("Failed to listen on pipe socket %s: %s\n",
- pipe_name, strerror(errno)));
- goto out;
- }
-
- state->ev_ctx = ev_ctx;
- state->msg_ctx = msg_ctx;
-
- DEBUG(10, ("Opened pipe socket fd %d for %s\n",
- state->fd, pipe_name));
-
- fde = tevent_add_fd(ev_ctx,
- state, state->fd, TEVENT_FD_READ,
- named_pipe_listener, state);
- if (!fde) {
- DEBUG(0, ("Failed to add event handler!\n"));
- goto out;
- }
-
- tevent_fd_set_auto_close(fde);
- return true;
-
-out:
- if (state->fd != -1) {
- close(state->fd);
- }
- TALLOC_FREE(state);
- return false;
-}
-
-static void named_pipe_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 sockaddr_un sunaddr;
- socklen_t len;
- int sd = -1;
-
- /* TODO: should we have a limit to the number of clients ? */
-
- len = sizeof(sunaddr);
-
- sd = accept(state->fd,
- (struct sockaddr *)(void *)&sunaddr, &len);
-
- if (sd == -1) {
- if (errno != EINTR) {
- DEBUG(6, ("Failed to get a valid socket [%s]\n",
- strerror(errno)));
- }
- return;
- }
-
- DEBUG(6, ("Accepted socket %d\n", sd));
-
- named_pipe_accept_function(state->ev_ctx,
- state->msg_ctx,
- state->ep.name,
- sd, NULL, 0);
-}
-
-
-/* This is the core of the rpc server.
- * Accepts connections from clients and process requests using the appropriate
- * dispatcher table. */
-
-static int named_pipe_destructor(struct named_pipe_client *npc)
-{
- if (npc->term_fn) {
- npc->term_fn(npc->private_data);
- }
- return 0;
-}
-
-struct named_pipe_client *named_pipe_client_init(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- const char *pipe_name,
- named_pipe_termination_fn *term_fn,
- uint16_t file_type,
- uint16_t device_state,
- uint64_t allocation_size,
- void *private_data)
-{
- struct named_pipe_client *npc;
-
- npc = talloc_zero(mem_ctx, struct named_pipe_client);
- if (npc == NULL) {
- DEBUG(0, ("Out of memory!\n"));
- return NULL;
- }
- talloc_set_destructor(npc, named_pipe_destructor);
-
- npc->pipe_name = talloc_strdup(npc, pipe_name);
- if (npc->pipe_name == NULL) {
- DEBUG(0, ("Out of memory!\n"));
- talloc_free(npc);
- return NULL;
- }
-
- npc->ev = ev_ctx;
- npc->msg_ctx = msg_ctx;
- npc->term_fn = term_fn;
- npc->private_data = private_data;
-
- npc->file_type = file_type;
- npc->device_state = device_state;
- npc->allocation_size = allocation_size;
-
- return npc;
-}
-
-static void named_pipe_accept_done(struct tevent_req *subreq);
-
-void named_pipe_accept_function(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- const char *pipe_name, int fd,
- named_pipe_termination_fn *term_fn,
- void *private_data)
-{
- struct named_pipe_client *npc;
- struct tstream_context *plain;
- struct tevent_req *subreq;
- int ret;
-
- npc = talloc_zero(ev_ctx, struct named_pipe_client);
- if (!npc) {
- DEBUG(0, ("Out of memory!\n"));
- close(fd);
- return;
- }
-
- npc->pipe_name = talloc_strdup(npc, pipe_name);
- if (npc->pipe_name == NULL) {
- DEBUG(0, ("Out of memory!\n"));
- TALLOC_FREE(npc);
- close(fd);
- return;
- }
- npc->ev = ev_ctx;
- npc->msg_ctx = msg_ctx;
- npc->term_fn = term_fn;
- npc->private_data = private_data;
-
- talloc_set_destructor(npc, named_pipe_destructor);
+ struct gensec_security *gensec = NULL;
+ NTSTATUS status;
- /* make sure socket is in NON blocking state */
- ret = set_blocking(fd, false);
- if (ret != 0) {
- DEBUG(2, ("Failed to make socket non-blocking\n"));
- TALLOC_FREE(npc);
- close(fd);
- return;
+ if (out == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
}
- ret = tstream_bsd_existing_socket(npc, fd, &plain);
- if (ret != 0) {
- DEBUG(2, ("Failed to create tstream socket\n"));
- TALLOC_FREE(npc);
- close(fd);
- return;
+ status = auth_generic_prepare(mem_ctx,
+ call->conn->remote_address,
+ call->conn->local_address,
+ "DCE/RPC",
+ &gensec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("Failed to prepare gensec: %s\n", nt_errstr(status));
+ return status;
}
- npc->file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
- npc->device_state = 0xff | 0x0400 | 0x0100;
- npc->allocation_size = 4096;
+ *out = gensec;
- subreq = tstream_npa_accept_existing_send(npc, npc->ev, plain,
- npc->file_type,
- npc->device_state,
- npc->allocation_size);
- if (!subreq) {
- DEBUG(2, ("Failed to start async accept procedure\n"));
- TALLOC_FREE(npc);
- close(fd);
- return;
- }
- tevent_req_set_callback(subreq, named_pipe_accept_done, npc);
+ return NT_STATUS_OK;
}
-static void named_pipe_packet_done(struct tevent_req *subreq);
-
-static void named_pipe_accept_done(struct tevent_req *subreq)
+void dcesrv_log_successful_authz(
+ struct dcesrv_call_state *call,
+ void *private_data)
{
- struct auth_session_info_transport *session_info_transport;
- struct named_pipe_client *npc =
- tevent_req_callback_data(subreq, struct named_pipe_client);
- int error;
- int ret;
-
- ret = tstream_npa_accept_existing_recv(subreq, &error, npc,
- &npc->tstream,
- &npc->remote_client_addr,
- &npc->remote_client_name,
- &npc->local_server_addr,
- &npc->local_server_name,
- &session_info_transport);
-
- npc->session_info = talloc_move(npc, &session_info_transport->session_info);
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct auth4_context *auth4_context = NULL;
+ struct dcesrv_auth *auth = call->auth_state;
+ enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
+ call->conn->endpoint->ep_description);
+ const char *auth_type = derpc_transport_string_by_transport(transport);
+ const char *transport_protection = AUTHZ_TRANSPORT_PROTECTION_NONE;
+ NTSTATUS status;
- TALLOC_FREE(subreq);
- if (ret != 0) {
- DEBUG(2, ("Failed to accept named pipe connection! (%s)\n",
- strerror(error)));
- TALLOC_FREE(npc);
+ if (frame == NULL) {
+ DBG_ERR("No memory\n");
return;
}
- ret = make_server_pipes_struct(npc,
- npc->msg_ctx,
- npc->pipe_name, NCACN_NP,
- npc->remote_client_addr,
- npc->local_server_addr,
- npc->session_info,
- &npc->p, &error);
- if (ret != 0) {
- DEBUG(2, ("Failed to create pipes_struct! (%s)\n",
- strerror(error)));
- goto fail;
- }
-
- npc->write_queue = tevent_queue_create(npc, "np_server_write_queue");
- if (!npc->write_queue) {
- DEBUG(2, ("Failed to set up write queue!\n"));
- goto fail;
- }
-
- /* And now start receiving and processing packets */
- subreq = dcerpc_read_ncacn_packet_send(npc, npc->ev, npc->tstream);
- if (!subreq) {
- DEBUG(2, ("Failed to start receving packets\n"));
- goto fail;
+ if (transport == NCACN_NP) {
+ transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
}
- tevent_req_set_callback(subreq, named_pipe_packet_process, npc);
- return;
-fail:
- DEBUG(2, ("Fatal error. Terminating client(%s) connection!\n",
- npc->remote_client_name));
- /* terminate client connection */
- talloc_free(npc);
- return;
-}
-
-void named_pipe_packet_process(struct tevent_req *subreq)
-{
- struct named_pipe_client *npc =
- tevent_req_callback_data(subreq, struct named_pipe_client);
- struct _output_data *out = &npc->p->out_data;
- DATA_BLOB recv_buffer = data_blob_null;
- struct ncacn_packet *pkt;
- NTSTATUS status;
- uint32_t to_send;
- size_t i;
- bool ok;
-
- status = dcerpc_read_ncacn_packet_recv(subreq, npc, &pkt, &recv_buffer);
- TALLOC_FREE(subreq);
+ become_root();
+ status = make_auth4_context(frame, &auth4_context);
+ unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
-
- /* dcerpc_read_ncacn_packet_recv() returns a full PDU */
- npc->p->in_data.pdu_needed_len = 0;
- npc->p->in_data.pdu = recv_buffer;
- if (dcerpc_get_endian_flag(&recv_buffer) & DCERPC_DREP_LE) {
- npc->p->endian = RPC_LITTLE_ENDIAN;
- } else {
- npc->p->endian = RPC_BIG_ENDIAN;
- }
- DEBUG(10, ("PDU is in %s Endian format!\n",
- npc->p->endian ? "Big" : "Little"));
- process_complete_pdu(npc->p, pkt);
-
- /* reset pipe state and free PDU */
- npc->p->in_data.pdu.length = 0;
- talloc_free(recv_buffer.data);
- talloc_free(pkt);
-
- /* this is needed because of the way DCERPC Binds work in
- * the RPC marshalling code */
- to_send = out->frag.length - out->current_pdu_sent;
- if (to_send > 0) {
-
- npc->iov = talloc_zero(npc, struct iovec);
- if (!npc->iov) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- npc->count = 1;
-
- npc->iov[0].iov_base = out->frag.data
- + out->current_pdu_sent;
- npc->iov[0].iov_len = to_send;
-
- out->current_pdu_sent += to_send;
- }
-
- /* this condition is false for bind packets, or when we haven't
- * yet got a full request, and need to wait for more data from
- * the client */
- while (out->data_sent_length < out->rdata.length) {
-
- ok = create_next_pdu(npc->p);
- if (!ok) {
- DEBUG(3, ("Failed to create next PDU!\n"));
- status = NT_STATUS_UNEXPECTED_IO_ERROR;
- goto fail;
- }
-
- npc->iov = talloc_realloc(npc, npc->iov,
- struct iovec, npc->count + 1);
- if (!npc->iov) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- npc->iov[npc->count].iov_base = out->frag.data;
- npc->iov[npc->count].iov_len = out->frag.length;
-
- npc->count++;
- }
-
- /* we still don't have a complete request, go back and wait for more
- * data */
- if (npc->count == 0) {
- /* Wait for the next packet */
- subreq = dcerpc_read_ncacn_packet_send(npc, npc->ev, npc->tstream);
- if (!subreq) {
- DEBUG(2, ("Failed to start receving packets\n"));
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- tevent_req_set_callback(subreq, named_pipe_packet_process, npc);
+ DBG_ERR("Unable to make auth context for authz log.\n");
+ TALLOC_FREE(frame);
return;
}
- DEBUG(10, ("Sending %u fragments in a total of %u bytes\n",
- (unsigned int)npc->count,
- (unsigned int)npc->p->out_data.data_sent_length));
-
- for (i = 0; i < npc->count; i++) {
- DEBUG(10, ("Sending PDU number: %d, PDU Length: %u\n",
- (unsigned int)i,
- (unsigned int)npc->iov[i].iov_len));
- dump_data(11, (const uint8_t *)npc->iov[i].iov_base,
- npc->iov[i].iov_len);
-
- subreq = tstream_writev_queue_send(npc,
- npc->ev,
- npc->tstream,
- npc->write_queue,
- (npc->iov + i),
- 1);
- if (!subreq) {
- DEBUG(2, ("Failed to send packet\n"));
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- tevent_req_set_callback(subreq, named_pipe_packet_done, npc);
- }
-
- return;
-
-fail:
- DEBUG(2, ("Fatal error(%s). "
- "Terminating client(%s) connection!\n",
- nt_errstr(status), npc->remote_client_name));
- /* terminate client connection */
- talloc_free(npc);
- return;
+ /*
+ * Log the authorization to this RPC interface. This
+ * covered ncacn_np pass-through auth, and anonymous
+ * DCE/RPC (eg epmapper, netlogon etc)
+ */
+ log_successful_authz_event(auth4_context->msg_ctx,
+ auth4_context->lp_ctx,
+ call->conn->remote_address,
+ call->conn->local_address,
+ "DCE/RPC",
+ auth_type,
+ transport_protection,
+ auth->session_info,
+ NULL /* client_audit_info */,
+ NULL /* server_audit_info */);
+
+ auth->auth_audited = true;
+
+ TALLOC_FREE(frame);
}
-static void named_pipe_packet_done(struct tevent_req *subreq)
+static int dcesrv_assoc_group_destructor(struct dcesrv_assoc_group *assoc_group)
{
- struct named_pipe_client *npc =
- tevent_req_callback_data(subreq, struct named_pipe_client);
- int sys_errno;
int ret;
-
- ret = tstream_writev_queue_recv(subreq, &sys_errno);
- TALLOC_FREE(subreq);
- if (ret == -1) {
- DEBUG(2, ("Writev failed!\n"));
- goto fail;
- }
-
- if (tevent_queue_length(npc->write_queue) > 0) {
- return;
- }
-
- if (npc->p->fault_state != 0) {
- DEBUG(2, ("Disconnect after fault\n"));
- sys_errno = EINVAL;
- goto fail;
- }
-
- /* clear out any data that may have been left around */
- npc->count = 0;
- TALLOC_FREE(npc->iov);
- data_blob_free(&npc->p->in_data.data);
- data_blob_free(&npc->p->out_data.frag);
- data_blob_free(&npc->p->out_data.rdata);
-
- talloc_free_children(npc->p->mem_ctx);
-
- /* Wait for the next packet */
- subreq = dcerpc_read_ncacn_packet_send(npc, npc->ev, npc->tstream);
- if (!subreq) {
- DEBUG(2, ("Failed to start receving packets\n"));
- sys_errno = ENOMEM;
- goto fail;
- }
- tevent_req_set_callback(subreq, named_pipe_packet_process, npc);
- return;
-
-fail:
- DEBUG(2, ("Fatal error(%s). "
- "Terminating client(%s) connection!\n",
- strerror(sys_errno), npc->remote_client_name));
- /* terminate client connection */
- talloc_free(npc);
- return;
-}
-
-/********************************************************************
- * Start listening on the tcp/ip socket
- ********************************************************************/
-
-static void dcerpc_ncacn_tcpip_listener(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data);
-
-int create_tcpip_socket(const struct sockaddr_storage *ifss, uint16_t *port)
-{
- int fd = -1;
-
- if (*port == 0) {
- uint16_t i;
-
- for (i = lp_rpc_low_port(); i <= lp_rpc_high_port(); i++) {
- fd = open_socket_in(SOCK_STREAM,
- i,
- 0,
- ifss,
- false);
- if (fd >= 0) {
- *port = i;
- break;
- }
- }
- } else {
- fd = open_socket_in(SOCK_STREAM,
- *port,
- 0,
- ifss,
- true);
- }
- if (fd == -1) {
- DEBUG(0, ("Failed to create socket on port %u!\n", *port));
- return -1;
- }
-
- DEBUG(10, ("Opened tcpip socket fd %d for port %u\n", fd, *port));
-
- return fd;
-}
-
-uint16_t setup_dcerpc_ncacn_tcpip_socket(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- const struct sockaddr_storage *ifss,
- uint16_t port)
-{
- struct dcerpc_ncacn_listen_state *state;
- struct tevent_fd *fde;
- int rc;
-
- state = talloc(ev_ctx, struct dcerpc_ncacn_listen_state);
- if (state == NULL) {
- DEBUG(0, ("setup_dcerpc_ncacn_tcpip_socket: Out of memory\n"));
- return 0;
- }
-
- state->fd = -1;
- state->ep.port = port;
- state->disconnect_fn = NULL;
-
- state->fd = create_tcpip_socket(ifss, &state->ep.port);
- if (state->fd == -1) {
- goto out;
- }
-
- state->ev_ctx = ev_ctx;
- state->msg_ctx = msg_ctx;
-
- /* ready to listen */
- set_socket_options(state->fd, "SO_KEEPALIVE");
- set_socket_options(state->fd, lp_socket_options());
-
- /* Set server socket to non-blocking for the accept. */
- set_blocking(state->fd, false);
-
- rc = listen(state->fd, SMBD_LISTEN_BACKLOG);
- if (rc == -1) {
- DEBUG(0,("setup_tcpip_socket: listen - %s\n", strerror(errno)));
- goto out;
- }
-
- DEBUG(10, ("setup_tcpip_socket: openened socket fd %d for port %u\n",
- state->fd, state->ep.port));
-
- fde = tevent_add_fd(state->ev_ctx,
- state,
- state->fd,
- TEVENT_FD_READ,
- dcerpc_ncacn_tcpip_listener,
- state);
- if (fde == NULL) {
- DEBUG(0, ("setup_tcpip_socket: Failed to add event handler!\n"));
- goto out;
- }
-
- tevent_fd_set_auto_close(fde);
-
- return state->ep.port;
-out:
- if (state->fd != -1) {
- close(state->fd);
+ ret = idr_remove(assoc_group->dce_ctx->assoc_groups_idr,
+ assoc_group->id);
+ if (ret != 0) {
+ DBG_ERR("Failed to remove assoc_group 0x%08x\n",
+ assoc_group->id);
}
- TALLOC_FREE(state);
-
return 0;
}
-static void dcerpc_ncacn_tcpip_listener(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data)
+static NTSTATUS dcesrv_assoc_group_new(struct dcesrv_call_state *call)
{
- struct dcerpc_ncacn_listen_state *state =
- talloc_get_type_abort(private_data,
- struct dcerpc_ncacn_listen_state);
- struct tsocket_address *cli_addr = NULL;
- struct tsocket_address *srv_addr = NULL;
- struct sockaddr_storage addr;
- socklen_t in_addrlen = sizeof(addr);
- int s = -1;
- int rc;
+ struct dcesrv_connection *conn = call->conn;
+ struct dcesrv_context *dce_ctx = conn->dce_ctx;
+ const struct dcesrv_endpoint *endpoint = conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+ struct dcesrv_assoc_group *assoc_group = NULL;
+ int id;
- s = accept(state->fd, (struct sockaddr *)(void *) &addr, &in_addrlen);
- if (s == -1) {
- if (errno != EINTR) {
- DEBUG(0,("tcpip_listener accept: %s\n",
- strerror(errno)));
- }
- return;
+ assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
+ if (assoc_group == NULL) {
+ return NT_STATUS_NO_MEMORY;
}
- rc = tsocket_address_bsd_from_sockaddr(state,
- (struct sockaddr *)(void *) &addr,
- in_addrlen,
- &cli_addr);
- if (rc < 0) {
- close(s);
- return;
+ id = idr_get_new_random(dce_ctx->assoc_groups_idr,
+ assoc_group,
+ 1,
+ UINT16_MAX);
+ if (id == -1) {
+ TALLOC_FREE(assoc_group);
+ DBG_ERR("Out of association groups!\n");
+ return NT_STATUS_RPC_OUT_OF_RESOURCES;
}
- rc = getsockname(s, (struct sockaddr *)(void *) &addr, &in_addrlen);
- if (rc < 0) {
- close(s);
- return;
- }
+ assoc_group->transport = transport;
+ assoc_group->id = id;
+ assoc_group->dce_ctx = dce_ctx;
- rc = tsocket_address_bsd_from_sockaddr(state,
- (struct sockaddr *)(void *) &addr,
- in_addrlen,
- &srv_addr);
- if (rc < 0) {
- close(s);
- return;
- }
+ call->conn->assoc_group = assoc_group;
- DEBUG(6, ("tcpip_listener: Accepted socket %d\n", s));
+ talloc_set_destructor(assoc_group, dcesrv_assoc_group_destructor);
- dcerpc_ncacn_accept(state->ev_ctx,
- state->msg_ctx,
- NCACN_IP_TCP,
- NULL,
- cli_addr,
- srv_addr,
- s,
- NULL);
+ return NT_STATUS_OK;
}
-/********************************************************************
- * Start listening on the ncalrpc socket
- ********************************************************************/
-
-static void dcerpc_ncalrpc_listener(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data);
-
-int create_dcerpc_ncalrpc_socket(const char *name)
+static NTSTATUS dcesrv_assoc_group_reference(struct dcesrv_call_state *call,
+ uint32_t assoc_group_id)
{
- int fd = -1;
-
- if (name == NULL) {
- name = "DEFAULT";
+ struct dcesrv_connection *conn = call->conn;
+ const struct dcesrv_endpoint *endpoint = conn->endpoint;
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(endpoint->ep_description);
+ struct dcesrv_assoc_group *assoc_group = NULL;
+ void *id_ptr = NULL;
+
+ /* find an association group given a assoc_group_id */
+ id_ptr = idr_find(conn->dce_ctx->assoc_groups_idr, assoc_group_id);
+ if (id_ptr == NULL) {
+ /*
+ * FIXME If the association group is not found it has
+ * been created in other process (preforking daemons).
+ * Until this is properly fixed we just create a new
+ * association group in this process
+ */
+ DBG_NOTICE("Failed to find assoc_group 0x%08x in this "
+ "server process, creating a new one\n",
+ assoc_group_id);
+ return dcesrv_assoc_group_new(call);
}
+ assoc_group = talloc_get_type_abort(id_ptr, struct dcesrv_assoc_group);
- if (!directory_create_or_exist(lp_ncalrpc_dir(), 0755)) {
- DEBUG(0, ("Failed to create ncalrpc directory %s - %s\n",
- lp_ncalrpc_dir(), strerror(errno)));
- return -1;
- }
+ if (assoc_group->transport != transport) {
+ const char *at =
+ derpc_transport_string_by_transport(
+ assoc_group->transport);
+ const char *ct =
+ derpc_transport_string_by_transport(
+ transport);
- fd = create_pipe_sock(lp_ncalrpc_dir(), name, 0755);
- if (fd == -1) {
- DEBUG(0, ("Failed to create ncalrpc socket! [%s/%s]\n",
- lp_ncalrpc_dir(), name));
- return -1;
+ DBG_NOTICE("assoc_group 0x%08x (transport %s) "
+ "is not available on transport %s\n",
+ assoc_group_id, at, ct);
+ return NT_STATUS_UNSUCCESSFUL;
}
- DEBUG(10, ("Opened ncalrpc socket fd %d for %s\n", fd, name));
-
- return fd;
+ conn->assoc_group = talloc_reference(conn, assoc_group);
+ return NT_STATUS_OK;
}
-bool setup_dcerpc_ncalrpc_socket(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- const char *name,
- dcerpc_ncacn_disconnect_fn fn)
+NTSTATUS dcesrv_assoc_group_find(
+ struct dcesrv_call_state *call,
+ void *private_data)
{
- struct dcerpc_ncacn_listen_state *state;
- struct tevent_fd *fde;
- int rc;
-
- state = talloc(ev_ctx, struct dcerpc_ncacn_listen_state);
- if (state == NULL) {
- DEBUG(0, ("Out of memory\n"));
- return false;
- }
-
- state->fd = -1;
- state->disconnect_fn = fn;
+ uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
- if (name == NULL) {
- name = "DEFAULT";
+ if (assoc_group_id != 0) {
+ return dcesrv_assoc_group_reference(call, assoc_group_id);
}
- state->ep.name = talloc_strdup(state, name);
- if (state->ep.name == NULL) {
- DEBUG(0, ("Out of memory\n"));
- talloc_free(state);
- return false;
- }
-
- state->fd = create_dcerpc_ncalrpc_socket(name);
- if (state->fd == -1) {
- goto out;
- }
-
- rc = listen(state->fd, 5);
- if (rc < 0) {
- DEBUG(0, ("Failed to listen on ncalrpc socket %s: %s\n",
- name, strerror(errno)));
- goto out;
- }
-
- state->ev_ctx = ev_ctx;
- state->msg_ctx = msg_ctx;
-
- /* Set server socket to non-blocking for the accept. */
- set_blocking(state->fd, false);
-
- fde = tevent_add_fd(state->ev_ctx,
- state,
- state->fd,
- TEVENT_FD_READ,
- dcerpc_ncalrpc_listener,
- state);
- if (fde == NULL) {
- DEBUG(0, ("Failed to add event handler for ncalrpc!\n"));
- goto out;
- }
-
- tevent_fd_set_auto_close(fde);
-
- return true;
-out:
- if (state->fd != -1) {
- close(state->fd);
- }
- TALLOC_FREE(state);
-
- return 0;
+ /* If not requested by client create a new association group */
+ return dcesrv_assoc_group_new(call);
}
-static void dcerpc_ncalrpc_listener(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data)
+void dcesrv_transport_terminate_connection(struct dcesrv_connection *dce_conn,
+ const char *reason)
{
- 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 sockaddr_un sunaddr;
- struct sockaddr *addr = (struct sockaddr *)(void *)&sunaddr;
- socklen_t len = sizeof(sunaddr);
- struct sockaddr_un sunaddr_server;
- struct sockaddr *addr_server = (struct sockaddr *)(void *)&sunaddr_server;
- socklen_t len_server = sizeof(sunaddr_server);
- int sd = -1;
- int rc;
-
- ZERO_STRUCT(sunaddr);
- ZERO_STRUCT(sunaddr_server);
-
- sd = accept(state->fd, addr, &len);
- if (sd == -1) {
- if (errno != EINTR) {
- DEBUG(0, ("ncalrpc accept() failed: %s\n", strerror(errno)));
- }
- return;
- }
-
- rc = tsocket_address_bsd_from_sockaddr(state,
- addr, len,
- &cli_addr);
- if (rc < 0) {
- close(sd);
- return;
- }
-
- rc = getsockname(sd, addr_server, &len_server);
- if (rc < 0) {
- close(sd);
- return;
- }
+ struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
+ dce_conn->transport.private_data,
+ struct dcerpc_ncacn_conn);
- rc = tsocket_address_bsd_from_sockaddr(state,
- addr_server,
- len_server,
- &srv_addr);
- if (rc < 0) {
- close(sd);
- return;
- }
-
- DEBUG(10, ("Accepted ncalrpc socket %s (fd: %d)\n",
- sunaddr.sun_path, sd));
-
- dcerpc_ncacn_accept(state->ev_ctx,
- state->msg_ctx,
- NCALRPC,
- state->ep.name,
- cli_addr, srv_addr, sd,
- state->disconnect_fn);
+ ncacn_terminate_connection(ncacn_conn, reason);
}
-struct dcerpc_ncacn_conn {
- enum dcerpc_transport_t transport;
-
- int sock;
-
- struct pipes_struct *p;
- dcerpc_ncacn_disconnect_fn disconnect_fn;
-
- struct tevent_context *ev_ctx;
- struct messaging_context *msg_ctx;
-
- struct tstream_context *tstream;
- struct tevent_queue *send_queue;
-
- struct tsocket_address *client;
- char *client_name;
- struct tsocket_address *server;
- char *server_name;
- struct auth_session_info *session_info;
-
- struct iovec *iov;
- size_t count;
-};
-
-static void dcerpc_ncacn_packet_process(struct tevent_req *subreq);
-static void dcerpc_ncacn_packet_done(struct tevent_req *subreq);
-
-void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- enum dcerpc_transport_t transport,
- const char *name,
- struct tsocket_address *cli_addr,
- struct tsocket_address *srv_addr,
- int s,
- dcerpc_ncacn_disconnect_fn fn) {
- struct dcerpc_ncacn_conn *ncacn_conn;
- struct tevent_req *subreq;
- char *pipe_name;
- NTSTATUS status;
- int sys_errno;
- uid_t uid;
- gid_t gid;
- int rc;
-
- DEBUG(10, ("dcerpc_ncacn_accept\n"));
-
- ncacn_conn = talloc_zero(ev_ctx, struct dcerpc_ncacn_conn);
- if (ncacn_conn == NULL) {
- DEBUG(0, ("Out of memory!\n"));
- close(s);
- return;
- }
-
- ncacn_conn->transport = transport;
- ncacn_conn->ev_ctx = ev_ctx;
- ncacn_conn->msg_ctx = msg_ctx;
- ncacn_conn->sock = s;
- ncacn_conn->disconnect_fn = fn;
-
- ncacn_conn->client = talloc_move(ncacn_conn, &cli_addr);
- if (tsocket_address_is_inet(ncacn_conn->client, "ip")) {
- ncacn_conn->client_name =
- tsocket_address_inet_addr_string(ncacn_conn->client,
- ncacn_conn);
- } else {
- ncacn_conn->client_name =
- tsocket_address_unix_path(ncacn_conn->client,
- ncacn_conn);
- }
- if (ncacn_conn->client_name == NULL) {
- DEBUG(0, ("Out of memory obtaining remote socket address as a string!\n"));
- talloc_free(ncacn_conn);
- close(s);
- return;
- }
-
- if (srv_addr != NULL) {
- ncacn_conn->server = talloc_move(ncacn_conn, &srv_addr);
-
- if (tsocket_address_is_inet(ncacn_conn->server, "ip")) {
- ncacn_conn->server_name =
- tsocket_address_inet_addr_string(ncacn_conn->server,
- ncacn_conn);
- } else {
- ncacn_conn->server_name =
- tsocket_address_unix_path(ncacn_conn->server,
- ncacn_conn);
- }
- if (ncacn_conn->server_name == NULL) {
- DEBUG(0, ("Out of memory obtaining local socket address as a string!\n"));
- talloc_free(ncacn_conn);
- close(s);
- return;
- }
- }
-
- switch (transport) {
- case NCACN_IP_TCP:
- pipe_name = tsocket_address_string(ncacn_conn->client,
- ncacn_conn);
- if (pipe_name == NULL) {
- close(s);
- talloc_free(ncacn_conn);
- return;
- }
-
- break;
- case NCALRPC:
- rc = getpeereid(s, &uid, &gid);
- if (rc < 0) {
- DEBUG(2, ("Failed to get ncalrpc connecting "
- "uid - %s!\n", strerror(errno)));
- } else {
- if (uid == sec_initial_uid()) {
- TALLOC_FREE(ncacn_conn->client);
-
- rc = tsocket_address_unix_from_path(ncacn_conn,
- "/root/ncalrpc_as_system",
- &ncacn_conn->client);
- if (rc < 0) {
- DEBUG(0, ("Out of memory building magic ncalrpc_as_system path!\n"));
- talloc_free(ncacn_conn);
- close(s);
- return;
- }
-
- TALLOC_FREE(ncacn_conn->client_name);
- ncacn_conn->client_name = tsocket_address_unix_path(ncacn_conn->client,
- ncacn_conn);
- if (ncacn_conn->client == NULL) {
- DEBUG(0, ("Out of memory getting magic ncalrpc_as_system string!\n"));
- talloc_free(ncacn_conn);
- close(s);
- return;
- }
- }
- }
- /* FALL TROUGH */
- case NCACN_NP:
- pipe_name = talloc_strdup(ncacn_conn,
- name);
- if (pipe_name == NULL) {
- close(s);
- talloc_free(ncacn_conn);
- return;
- }
- break;
- default:
- DEBUG(0, ("unknown dcerpc transport: %u!\n",
- transport));
- talloc_free(ncacn_conn);
- close(s);
- return;
- }
-
- rc = set_blocking(s, false);
- if (rc < 0) {
- DEBUG(2, ("Failed to set dcerpc socket to non-blocking\n"));
- talloc_free(ncacn_conn);
- close(s);
- return;
- }
-
- /*
- * As soon as we have tstream_bsd_existing_socket set up it will
- * take care of closing the socket.
- */
- rc = tstream_bsd_existing_socket(ncacn_conn, s, &ncacn_conn->tstream);
- if (rc < 0) {
- DEBUG(2, ("Failed to create tstream socket for dcerpc\n"));
- talloc_free(ncacn_conn);
- close(s);
- return;
- }
-
- if (ncacn_conn->session_info == NULL) {
- /*
- * TODO: use auth_anonymous_session_info() here?
- */
- status = make_session_info_guest(ncacn_conn,
- &ncacn_conn->session_info);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2, ("Failed to create "
- "make_session_info_guest - %s\n",
- nt_errstr(status)));
- talloc_free(ncacn_conn);
- return;
- }
- }
-
- rc = make_server_pipes_struct(ncacn_conn,
- ncacn_conn->msg_ctx,
- pipe_name,
- ncacn_conn->transport,
- ncacn_conn->client,
- ncacn_conn->server,
- ncacn_conn->session_info,
- &ncacn_conn->p,
- &sys_errno);
- if (rc < 0) {
- DEBUG(2, ("Failed to create pipe struct - %s",
- strerror(sys_errno)));
- talloc_free(ncacn_conn);
- return;
- }
-
- ncacn_conn->send_queue = tevent_queue_create(ncacn_conn,
- "dcerpc send queue");
- if (ncacn_conn->send_queue == NULL) {
- DEBUG(0, ("Out of memory building dcerpc send queue!\n"));
- talloc_free(ncacn_conn);
- return;
- }
-
- subreq = dcerpc_read_ncacn_packet_send(ncacn_conn,
- ncacn_conn->ev_ctx,
- ncacn_conn->tstream);
- if (subreq == NULL) {
- DEBUG(2, ("Failed to send ncacn packet\n"));
- talloc_free(ncacn_conn);
- return;
- }
-
- tevent_req_set_callback(subreq, dcerpc_ncacn_packet_process, ncacn_conn);
+static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
+ const char *reason)
+{
+ if (reason == NULL) {
+ reason = "Unknown reason";
+ }
- DEBUG(10, ("dcerpc_ncacn_accept done\n"));
+ DBG_NOTICE("Terminating connection - '%s'\n", reason);
- return;
+ talloc_free(conn);
}
-static void dcerpc_ncacn_packet_process(struct tevent_req *subreq)
+NTSTATUS dcesrv_endpoint_by_ncacn_np_name(struct dcesrv_context *dce_ctx,
+ const char *pipe_name,
+ struct dcesrv_endpoint **out)
{
- struct dcerpc_ncacn_conn *ncacn_conn =
- tevent_req_callback_data(subreq, struct dcerpc_ncacn_conn);
+ struct dcesrv_endpoint *e = NULL;
- struct _output_data *out = &ncacn_conn->p->out_data;
- DATA_BLOB recv_buffer = data_blob_null;
- struct ncacn_packet *pkt;
- uint32_t to_send;
- NTSTATUS status;
- bool ok;
+ for (e = dce_ctx->endpoint_list; e; e = e->next) {
+ enum dcerpc_transport_t transport =
+ dcerpc_binding_get_transport(e->ep_description);
+ const char *endpoint = NULL;
- status = dcerpc_read_ncacn_packet_recv(subreq, ncacn_conn, &pkt, &recv_buffer);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- if (ncacn_conn->disconnect_fn != NULL) {
- ok = ncacn_conn->disconnect_fn(ncacn_conn->p);
- if (!ok) {
- DEBUG(3, ("Failed to call disconnect function\n"));
- }
+ if (transport != NCACN_NP) {
+ continue;
}
- goto fail;
- }
-
- /* dcerpc_read_ncacn_packet_recv() returns a full PDU */
- ncacn_conn->p->in_data.pdu_needed_len = 0;
- ncacn_conn->p->in_data.pdu = recv_buffer;
- if (dcerpc_get_endian_flag(&recv_buffer) & DCERPC_DREP_LE) {
- ncacn_conn->p->endian = RPC_LITTLE_ENDIAN;
- } else {
- ncacn_conn->p->endian = RPC_BIG_ENDIAN;
- }
- DEBUG(10, ("PDU is in %s Endian format!\n",
- ncacn_conn->p->endian ? "Big" : "Little"));
- process_complete_pdu(ncacn_conn->p, pkt);
-
- /* reset pipe state and free PDU */
- ncacn_conn->p->in_data.pdu.length = 0;
- talloc_free(recv_buffer.data);
- talloc_free(pkt);
-
- /*
- * This is needed because of the way DCERPC binds work in the RPC
- * marshalling code
- */
- to_send = out->frag.length - out->current_pdu_sent;
- if (to_send > 0) {
- DEBUG(10, ("Current_pdu_len = %u, "
- "current_pdu_sent = %u "
- "Returning %u bytes\n",
- (unsigned int)out->frag.length,
- (unsigned int)out->current_pdu_sent,
- (unsigned int)to_send));
-
- ncacn_conn->iov = talloc_zero(ncacn_conn, struct iovec);
- if (ncacn_conn->iov == NULL) {
- status = NT_STATUS_NO_MEMORY;
- DEBUG(3, ("Out of memory!\n"));
- goto fail;
+ endpoint = dcerpc_binding_get_string_option(e->ep_description,
+ "endpoint");
+ if (endpoint == NULL) {
+ continue;
}
- ncacn_conn->count = 1;
-
- ncacn_conn->iov[0].iov_base = out->frag.data
- + out->current_pdu_sent;
- ncacn_conn->iov[0].iov_len = to_send;
- out->current_pdu_sent += to_send;
- }
-
- /*
- * This condition is false for bind packets, or when we haven't yet got
- * a full request, and need to wait for more data from the client
- */
- while (out->data_sent_length < out->rdata.length) {
- ok = create_next_pdu(ncacn_conn->p);
- if (!ok) {
- DEBUG(3, ("Failed to create next PDU!\n"));
- status = NT_STATUS_UNEXPECTED_IO_ERROR;
- goto fail;
+ if (strncmp(endpoint, "\\pipe\\", 6) == 0) {
+ endpoint += 6;
}
- ncacn_conn->iov = talloc_realloc(ncacn_conn,
- ncacn_conn->iov,
- struct iovec,
- ncacn_conn->count + 1);
- if (ncacn_conn->iov == NULL) {
- DEBUG(3, ("Out of memory!\n"));
- status = NT_STATUS_NO_MEMORY;
- goto fail;
+ if (strequal(endpoint, pipe_name)) {
+ *out = e;
+ return NT_STATUS_OK;
}
-
- ncacn_conn->iov[ncacn_conn->count].iov_base = out->frag.data;
- ncacn_conn->iov[ncacn_conn->count].iov_len = out->frag.length;
-
- DEBUG(10, ("PDU number: %d, PDU Length: %u\n",
- (unsigned int) ncacn_conn->count,
- (unsigned int) ncacn_conn->iov[ncacn_conn->count].iov_len));
- dump_data(11, (const uint8_t *) ncacn_conn->iov[ncacn_conn->count].iov_base,
- ncacn_conn->iov[ncacn_conn->count].iov_len);
- ncacn_conn->count++;
}
- /*
- * We still don't have a complete request, go back and wait for more
- * data.
- */
- if (ncacn_conn->count == 0) {
- /* Wait for the next packet */
- subreq = dcerpc_read_ncacn_packet_send(ncacn_conn,
- ncacn_conn->ev_ctx,
- ncacn_conn->tstream);
- if (subreq == NULL) {
- DEBUG(2, ("Failed to start receving packets\n"));
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- tevent_req_set_callback(subreq, dcerpc_ncacn_packet_process, ncacn_conn);
- return;
- }
-
- DEBUG(10, ("Sending a total of %u bytes\n",
- (unsigned int)ncacn_conn->p->out_data.data_sent_length));
-
- subreq = tstream_writev_queue_send(ncacn_conn,
- ncacn_conn->ev_ctx,
- ncacn_conn->tstream,
- ncacn_conn->send_queue,
- ncacn_conn->iov,
- ncacn_conn->count);
- if (subreq == NULL) {
- DEBUG(2, ("Failed to send packet\n"));
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- tevent_req_set_callback(subreq, dcerpc_ncacn_packet_done, ncacn_conn);
- return;
-
-fail:
- DEBUG(3, ("Terminating client(%s) connection! - '%s'\n",
- ncacn_conn->client_name, nt_errstr(status)));
-
- /* Terminate client connection */
- talloc_free(ncacn_conn);
- return;
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
-static void dcerpc_ncacn_packet_done(struct tevent_req *subreq)
+struct pipes_struct *dcesrv_get_pipes_struct(struct dcesrv_connection *conn)
{
- struct dcerpc_ncacn_conn *ncacn_conn =
- tevent_req_callback_data(subreq, struct dcerpc_ncacn_conn);
- NTSTATUS status = NT_STATUS_OK;
- int sys_errno;
- int rc;
-
- rc = tstream_writev_queue_recv(subreq, &sys_errno);
- TALLOC_FREE(subreq);
- if (rc < 0) {
- DEBUG(2, ("Writev failed!\n"));
- status = map_nt_error_from_unix(sys_errno);
- goto fail;
- }
-
- if (ncacn_conn->p->fault_state != 0) {
- DEBUG(2, ("Disconnect after fault\n"));
- sys_errno = EINVAL;
- goto fail;
- }
-
- /* clear out any data that may have been left around */
- ncacn_conn->count = 0;
- TALLOC_FREE(ncacn_conn->iov);
- data_blob_free(&ncacn_conn->p->in_data.data);
- data_blob_free(&ncacn_conn->p->out_data.frag);
- data_blob_free(&ncacn_conn->p->out_data.rdata);
-
- talloc_free_children(ncacn_conn->p->mem_ctx);
-
- /* Wait for the next packet */
- subreq = dcerpc_read_ncacn_packet_send(ncacn_conn,
- ncacn_conn->ev_ctx,
- ncacn_conn->tstream);
- if (subreq == NULL) {
- DEBUG(2, ("Failed to start receving packets\n"));
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- tevent_req_set_callback(subreq, dcerpc_ncacn_packet_process, ncacn_conn);
- return;
-
-fail:
- DEBUG(3, ("Terminating client(%s) connection! - '%s'\n",
- ncacn_conn->client_name, nt_errstr(status)));
+ struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
+ conn->transport.private_data,
+ struct dcerpc_ncacn_conn);
- /* Terminate client connection */
- talloc_free(ncacn_conn);
- return;
+ return &ncacn_conn->p;
}
/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */