1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-27 03:21:53 +03:00
samba-mirror/source3/rpc_server/rpc_server.c

712 lines
18 KiB
C
Raw Normal View History

/*
Unix SMB/Netbios implementation.
Generic infrstructure for RPC Daemons
Copyright (C) Simo Sorce 2010
Copyright (C) Andrew Bartlett 2011
2011-07-21 15:13:35 +04:00
Copyright (C) Andreas Schneider 2011
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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 "rpc_dce.h"
#include "librpc/gen_ndr/netlogon.h"
#include "librpc/gen_ndr/auth.h"
#include "lib/tsocket/tsocket.h"
#include "libcli/named_pipe_auth/npa_tstream.h"
#include "../auth/auth_sam_reply.h"
#include "auth.h"
#include "rpc_server/rpc_ncacn_np.h"
#include "rpc_server/srv_pipe_hnd.h"
#include "rpc_server/srv_pipe.h"
#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 {
int fd;
struct tevent_context *ev_ctx;
struct messaging_context *msg_ctx;
struct dcesrv_context *dce_ctx;
struct dcesrv_endpoint *endpoint;
dcerpc_ncacn_termination_fn termination_fn;
void *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);
}
}
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
{
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
conn->transport.private_data,
struct dcerpc_ncacn_conn);
if (ncacn_conn->termination_fn != NULL) {
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
}
return 0;
}
NTSTATUS dcerpc_ncacn_conn_init(TALLOC_CTX *mem_ctx,
struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
struct dcesrv_context *dce_ctx,
struct dcesrv_endpoint *endpoint,
dcerpc_ncacn_termination_fn term_fn,
void *termination_data,
struct dcerpc_ncacn_conn **out)
{
struct dcerpc_ncacn_conn *ncacn_conn = NULL;
ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
if (ncacn_conn == NULL) {
return NT_STATUS_NO_MEMORY;
}
ncacn_conn->ev_ctx = ev_ctx;
ncacn_conn->msg_ctx = msg_ctx;
ncacn_conn->dce_ctx = dce_ctx;
ncacn_conn->endpoint = endpoint;
ncacn_conn->sock = -1;
ncacn_conn->termination_fn = term_fn;
ncacn_conn->termination_data = termination_data;
*out = ncacn_conn;
return NT_STATUS_OK;
}
static void dcesrv_ncacn_np_accept_done(struct tevent_req *subreq);
static void dcesrv_ncacn_accept_step2(struct dcerpc_ncacn_conn *ncacn_conn);
static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
const char *reason);
void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
struct dcesrv_context *dce_ctx,
struct dcesrv_endpoint *e,
struct tsocket_address **cli_addr,
struct tsocket_address **srv_addr,
int s,
dcerpc_ncacn_termination_fn termination_fn,
void *termination_data)
{
enum dcerpc_transport_t transport =
dcerpc_binding_get_transport(e->ep_description);
struct dcerpc_ncacn_conn *ncacn_conn;
NTSTATUS status;
int rc;
DBG_DEBUG("dcerpc_ncacn_accept\n");
status = dcerpc_ncacn_conn_init(ev_ctx,
ev_ctx,
msg_ctx,
dce_ctx,
e,
termination_fn,
termination_data,
&ncacn_conn);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("Failed to initialize dcerpc_ncacn_connection: %s\n",
nt_errstr(status));
close(s);
return;
}
ncacn_conn->sock = s;
if ((cli_addr != NULL) && (*cli_addr != NULL)) {
ncacn_conn->remote_client_addr = talloc_move(
ncacn_conn, cli_addr);
if (tsocket_address_is_inet(ncacn_conn->remote_client_addr, "ip")) {
ncacn_conn->remote_client_name =
tsocket_address_inet_addr_string(ncacn_conn->remote_client_addr,
ncacn_conn);
} else {
ncacn_conn->remote_client_name =
tsocket_address_unix_path(ncacn_conn->remote_client_addr,
ncacn_conn);
}
if (ncacn_conn->remote_client_name == NULL) {
DBG_ERR("Out of memory obtaining remote socket address as a string!\n");
ncacn_terminate_connection(ncacn_conn, "No memory");
close(s);
return;
}
}
if ((srv_addr != NULL) && (*srv_addr != NULL)) {
ncacn_conn->local_server_addr = talloc_move(
ncacn_conn, srv_addr);
if (tsocket_address_is_inet(ncacn_conn->local_server_addr, "ip")) {
ncacn_conn->local_server_name =
tsocket_address_inet_addr_string(ncacn_conn->local_server_addr,
ncacn_conn);
} else {
ncacn_conn->local_server_name =
tsocket_address_unix_path(ncacn_conn->local_server_addr,
ncacn_conn);
}
if (ncacn_conn->local_server_name == NULL) {
DBG_ERR("No memory\n");
ncacn_terminate_connection(ncacn_conn, "No memory");
close(s);
return;
}
}
rc = set_blocking(s, false);
if (rc < 0) {
DBG_WARNING("Failed to set dcerpc socket to non-blocking\n");
ncacn_terminate_connection(ncacn_conn, strerror(errno));
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) {
DBG_WARNING("Failed to create tstream socket for dcerpc\n");
ncacn_terminate_connection(ncacn_conn, "No memory");
close(s);
return;
}
if (transport == NCACN_NP) {
struct tevent_req *subreq = NULL;
uint64_t allocation_size = 4096;
uint16_t device_state = 0xff | 0x0400 | 0x0100;
uint16_t file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
subreq = tstream_npa_accept_existing_send(ncacn_conn,
ncacn_conn->ev_ctx,
ncacn_conn->tstream,
file_type,
device_state,
allocation_size);
if (subreq == NULL) {
ncacn_terminate_connection(ncacn_conn, "No memory");
return;
}
tevent_req_set_callback(subreq, dcesrv_ncacn_np_accept_done,
ncacn_conn);
return;
}
dcesrv_ncacn_accept_step2(ncacn_conn);
}
static void dcesrv_ncacn_np_accept_done(struct tevent_req *subreq)
{
struct dcerpc_ncacn_conn *ncacn_conn = tevent_req_callback_data(
subreq, struct dcerpc_ncacn_conn);
struct auth_session_info_transport *session_info_transport = NULL;
int error;
int ret;
ret = tstream_npa_accept_existing_recv(subreq, &error, ncacn_conn,
&ncacn_conn->tstream,
&ncacn_conn->remote_client_addr,
&ncacn_conn->remote_client_name,
&ncacn_conn->local_server_addr,
&ncacn_conn->local_server_name,
&session_info_transport);
ncacn_conn->session_info = talloc_move(ncacn_conn,
&session_info_transport->session_info);
TALLOC_FREE(subreq);
if (ret != 0) {
DBG_ERR("Failed to accept named pipe connection: %s\n",
strerror(error));
ncacn_terminate_connection(ncacn_conn, strerror(errno));
return;
}
dcesrv_ncacn_accept_step2(ncacn_conn);
}
static void dcesrv_ncacn_accept_step2(struct dcerpc_ncacn_conn *ncacn_conn)
{
char *pipe_name = NULL;
uid_t uid;
gid_t gid;
int rc;
enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
ncacn_conn->endpoint->ep_description);
const char *endpoint = dcerpc_binding_get_string_option(
ncacn_conn->endpoint->ep_description, "endpoint");
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
struct dcesrv_connection *dcesrv_conn = NULL;
NTSTATUS status;
switch (transport) {
case NCACN_IP_TCP:
pipe_name = tsocket_address_string(ncacn_conn->remote_client_addr,
ncacn_conn);
if (pipe_name == NULL) {
DBG_ERR("No memory\n");
ncacn_terminate_connection(ncacn_conn, "No memory");
return;
}
break;
case NCALRPC:
rc = getpeereid(ncacn_conn->sock, &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->remote_client_addr);
rc = tsocket_address_unix_from_path(ncacn_conn,
AS_SYSTEM_MAGIC_PATH_TOKEN,
&ncacn_conn->remote_client_addr);
if (rc < 0) {
DBG_ERR("No memory\n");
ncacn_terminate_connection(ncacn_conn, "No memory");
return;
}
TALLOC_FREE(ncacn_conn->remote_client_name);
ncacn_conn->remote_client_name
= tsocket_address_unix_path(ncacn_conn->remote_client_addr,
ncacn_conn);
if (ncacn_conn->remote_client_name == NULL) {
DBG_ERR("No memory\n");
ncacn_terminate_connection(ncacn_conn, "No memory");
return;
}
}
}
FALL_THROUGH;
case NCACN_NP:
pipe_name = talloc_strdup(ncacn_conn, endpoint);
if (pipe_name == NULL) {
DBG_ERR("No memory\n");
ncacn_terminate_connection(ncacn_conn, "No memory");
return;
}
break;
default:
DBG_ERR("unknown dcerpc transport: %u!\n", transport);
ncacn_terminate_connection(ncacn_conn,
"Unknown DCE/RPC transport");
return;
}
if (ncacn_conn->session_info == NULL) {
status = make_session_info_anonymous(ncacn_conn,
&ncacn_conn->session_info);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("Failed to create anonymous session info: "
"%s\n", nt_errstr(status));
ncacn_terminate_connection(ncacn_conn,
nt_errstr(status));
return;
}
}
rc = make_base_pipes_struct(ncacn_conn,
ncacn_conn->msg_ctx,
pipe_name,
transport,
ncacn_conn->remote_client_addr,
ncacn_conn->local_server_addr,
&ncacn_conn->p);
if (rc != 0) {
const char *errstr = strerror(rc);
DBG_ERR("Failed to create pipe struct: %s\n", errstr);
ncacn_terminate_connection(ncacn_conn, errstr);
return;
}
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
/*
* This fills in dcesrv_conn->endpoint with the endpoint
* associated with the socket. From this point on we know
* which (group of) services we are handling, but not the
* specific interface.
*/
status = dcesrv_endpoint_connect(ncacn_conn->dce_ctx,
ncacn_conn,
ncacn_conn->endpoint,
ncacn_conn->session_info,
ncacn_conn->ev_ctx,
DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
&dcesrv_conn);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("Failed to connect to endpoint: %s\n",
nt_errstr(status));
ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
return;
}
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
dcesrv_conn->transport.private_data = ncacn_conn;
dcesrv_conn->transport.report_output_data =
dcesrv_sock_report_output_data;
dcesrv_conn->transport.terminate_connection =
dcesrv_transport_terminate_connection;
dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn,
"dcesrv send queue");
if (dcesrv_conn->send_queue == NULL) {
status = NT_STATUS_NO_MEMORY;
DBG_ERR("Failed to create send queue: %s\n",
nt_errstr(status));
ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
return;
}
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
dcesrv_conn->local_address = ncacn_conn->local_server_addr;
dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
status = dcesrv_connection_loop_start(dcesrv_conn);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("Failed to start dcesrv_connection loop: %s\n",
nt_errstr(status));
ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
}
DBG_DEBUG("dcerpc_ncacn_accept done\n");
return;
}
NTSTATUS dcesrv_auth_gensec_prepare(TALLOC_CTX *mem_ctx,
struct dcesrv_call_state *call,
struct gensec_security **out)
{
struct gensec_security *gensec = NULL;
NTSTATUS status;
if (out == NULL) {
return NT_STATUS_INVALID_PARAMETER;
}
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;
}
*out = gensec;
return NT_STATUS_OK;
}
void dcesrv_log_successful_authz(struct dcesrv_call_state *call)
{
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;
if (frame == NULL) {
DBG_ERR("No memory");
return;
}
if (transport == NCACN_NP) {
transport_protection = AUTHZ_TRANSPORT_PROTECTION_SMB;
}
become_root();
status = make_auth4_context(frame, &auth4_context);
unbecome_root();
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("Unable to make auth context for authz log.\n");
TALLOC_FREE(frame);
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);
auth->auth_audited = true;
TALLOC_FREE(frame);
}
static NTSTATUS dcesrv_assoc_group_new(struct dcesrv_call_state *call,
uint32_t assoc_group_id)
{
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;
assoc_group = talloc_zero(conn, struct dcesrv_assoc_group);
if (assoc_group == NULL) {
return NT_STATUS_NO_MEMORY;
}
assoc_group->transport = transport;
assoc_group->id = assoc_group_id;
assoc_group->dce_ctx = dce_ctx;
call->conn->assoc_group = assoc_group;
return NT_STATUS_OK;
}
NTSTATUS dcesrv_assoc_group_find(struct dcesrv_call_state *call)
{
uint32_t assoc_group_id = call->pkt.u.bind.assoc_group_id;
/* If not requested by client create a new association group */
if (assoc_group_id == 0) {
assoc_group_id = 0x53F0;
}
return dcesrv_assoc_group_new(call, assoc_group_id);
}
s3:rpc_server: Switch to core dcerpc server loop This commit finally switches the RPC server implementation. At the same we have to do other related changes to keep code compiling and test environments running. First avoid moving the session_info into the allocated pipes_struct memory context as it is owned now by the core RPC server, and the s3compat pidl compiler will update the pipes_struct session_info before dispatching the call with dcesrv_call->auth_state->session_info. Also, fix a segfault in the endpoint mapper daemon when it tries to delete the endpoints previously registered over a NCALRPC connection. If we have: rpc_server : epmapper = external rpc_server : lsarpc = external rpc_daemon : epmd = fork rpc_daemon : lsasd = fork The sequence is: * The endpoint mapper starts (start_epmd in source3/smbd/server.c) * The lsarpc daemon starts (start_lsasd in source3/smbd/server.c) * The lsarpc daemon creates the sockets and registers its endpoints (rpc_ep_register in source3/rpc_server/lsasd.c) * The endpoint registration code opens a NCALRPC connection to the endpoint mapper daemon (ep_register in source3/librpc/rpc/dcerpc_ep.c) and keeps it open to re-register if the endpoint mapper daemon dies (rpc_ep_register_loop in source3/rpc_server/rpc_ep_register.c) * When the endpoint mapper daemon accepts a NCALRPC connection it sets a termination function (srv_epmapper_delete_endpoints) * Suppose the lsarpc daemon exits. The NCALRPC connection termination function is called. * The termination function tries to delete all endpoints registered by that connection by calling _epm_Delete * _epm_Delete calls is_privileged_pipe which access to pipes_struct->session_info. As the call to _epm_Delete occurs outside of the PIDL generated code, the pipes_stuct->session_info is NULL. This commit also sets pipes_struct->session_info from the dcerpc_connection before calling _epm_Delete. As the core rpc server supports security context multiplexing we need to pass the dcesrv_connection to the termination function and let the implementation pick a auth context. In the case of the endpoint mapper the termination function has to pick one of type NCALRPC_AS_SYSTEM to check if the connection is privileged and delete the endpoints registered by the connection being closed. Finally, the samba.tests.dcerpc.raw_protocol testsuite passes against the ad_member environment. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2019-12-05 13:45:54 +03:00
void dcesrv_transport_terminate_connection(struct dcesrv_connection *dce_conn,
const char *reason)
{
struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
dce_conn->transport.private_data,
struct dcerpc_ncacn_conn);
ncacn_terminate_connection(ncacn_conn, reason);
}
static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
const char *reason)
{
if (reason == NULL) {
reason = "Unknown reason";
}
DBG_NOTICE("Terminating connection - '%s'\n", reason);
talloc_free(conn);
}
NTSTATUS dcesrv_endpoint_by_ncacn_np_name(struct dcesrv_context *dce_ctx,
const char *pipe_name,
struct dcesrv_endpoint **out)
{
struct dcesrv_endpoint *e = NULL;
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;
if (transport != NCACN_NP) {
continue;
}
endpoint = dcerpc_binding_get_string_option(e->ep_description,
"endpoint");
if (endpoint == NULL) {
continue;
}
if (strncmp(endpoint, "\\pipe\\", 6) == 0) {
endpoint += 6;
}
if (strequal(endpoint, pipe_name)) {
*out = e;
return NT_STATUS_OK;
}
}
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
struct pipes_struct *dcesrv_get_pipes_struct(struct dcesrv_connection *conn)
{
struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
conn->transport.private_data,
struct dcerpc_ncacn_conn);
return ncacn_conn->p;
}
/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */