mirror of
https://github.com/samba-team/samba.git
synced 2025-01-08 21:18:16 +03:00
s3:rpc_client: Add local_np_connect()
This will be used for internal pipe connects. It starts samba_dcerpc on demand if it's not there yet, so long as smb.conf [global] has "rpc start on demand helpers = true" (the default setting). Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
parent
3ca7c640da
commit
4d75f08fd2
780
source3/rpc_client/local_np.c
Normal file
780
source3/rpc_client/local_np.c
Normal file
@ -0,0 +1,780 @@
|
||||
/*
|
||||
* Unix SMB/CIFS implementation.
|
||||
*
|
||||
* 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 "source3/include/includes.h"
|
||||
#include <spawn.h>
|
||||
#include "local_np.h"
|
||||
#include "lib/async_req/async_sock.h"
|
||||
#include "librpc/gen_ndr/ndr_named_pipe_auth.h"
|
||||
#include "libcli/named_pipe_auth/npa_tstream.h"
|
||||
#include "libcli/named_pipe_auth/tstream_u32_read.h"
|
||||
#include "lib/util/tevent_unix.h"
|
||||
#include "auth/auth_util.h"
|
||||
|
||||
/**
|
||||
* @file local_np.c
|
||||
*
|
||||
* Connect to a local named pipe by connecting to
|
||||
* samba-dcerpcd. Start samba-dcerpcd if it isn't
|
||||
* already running.
|
||||
*/
|
||||
|
||||
extern bool override_logfile;
|
||||
|
||||
struct np_sock_connect_state {
|
||||
struct tevent_context *ev;
|
||||
struct samba_sockaddr addr;
|
||||
const struct named_pipe_auth_req *npa_req;
|
||||
struct named_pipe_auth_rep *npa_rep;
|
||||
|
||||
DATA_BLOB npa_blob;
|
||||
struct iovec iov;
|
||||
|
||||
int sock;
|
||||
struct tevent_req *subreq;
|
||||
struct tstream_context *transport;
|
||||
struct tstream_context *npa_stream;
|
||||
};
|
||||
|
||||
static void np_sock_connect_cleanup(
|
||||
struct tevent_req *req, enum tevent_req_state req_state);
|
||||
static void np_sock_connect_before(void *private_data);
|
||||
static void np_sock_connect_after(void *private_data);
|
||||
static void np_sock_connect_connected(struct tevent_req *subreq);
|
||||
static void np_sock_connect_written(struct tevent_req *subreq);
|
||||
static void np_sock_connect_read_done(struct tevent_req *subreq);
|
||||
|
||||
static struct tevent_req *np_sock_connect_send(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
const char *sockpath,
|
||||
const struct named_pipe_auth_req *npa_req)
|
||||
{
|
||||
struct tevent_req *req = NULL;
|
||||
struct np_sock_connect_state *state = NULL;
|
||||
size_t len;
|
||||
int ret;
|
||||
bool ok;
|
||||
|
||||
req = tevent_req_create(mem_ctx, &state, struct np_sock_connect_state);
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
state->ev = ev;
|
||||
state->npa_req = npa_req;
|
||||
state->sock = -1;
|
||||
state->addr.u.un.sun_family = AF_UNIX;
|
||||
|
||||
state->npa_rep = talloc_zero(state, struct named_pipe_auth_rep);
|
||||
if (tevent_req_nomem(state->npa_rep, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
tevent_req_set_cleanup_fn(req, np_sock_connect_cleanup);
|
||||
|
||||
state->addr.sa_socklen = sizeof(struct sockaddr_un);
|
||||
len = strlcpy(state->addr.u.un.sun_path,
|
||||
sockpath,
|
||||
sizeof(state->addr.u.un.sun_path));
|
||||
if (len >= sizeof(state->addr.u.un.sun_path)) {
|
||||
tevent_req_error(req, ENAMETOOLONG);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
state->sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (state->sock == -1) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
ret = set_blocking(state->sock, false);
|
||||
if (ret == -1) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
ok = set_close_on_exec(state->sock);
|
||||
if (!ok) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
state->subreq = async_connect_send(
|
||||
state,
|
||||
ev,
|
||||
state->sock,
|
||||
&state->addr.u.sa,
|
||||
state->addr.sa_socklen,
|
||||
np_sock_connect_before,
|
||||
np_sock_connect_after,
|
||||
NULL);
|
||||
if (tevent_req_nomem(state->subreq, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
tevent_req_set_callback(state->subreq, np_sock_connect_connected, req);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void np_sock_connect_cleanup(
|
||||
struct tevent_req *req, enum tevent_req_state req_state)
|
||||
{
|
||||
struct np_sock_connect_state *state = tevent_req_data(
|
||||
req, struct np_sock_connect_state);
|
||||
|
||||
TALLOC_FREE(state->subreq);
|
||||
TALLOC_FREE(state->transport);
|
||||
|
||||
if (state->sock != -1) {
|
||||
close(state->sock);
|
||||
state->sock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void np_sock_connect_before(void *private_data)
|
||||
{
|
||||
become_root();
|
||||
}
|
||||
|
||||
static void np_sock_connect_after(void *private_data)
|
||||
{
|
||||
unbecome_root();
|
||||
}
|
||||
|
||||
static void np_sock_connect_connected(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct np_sock_connect_state *state = tevent_req_data(
|
||||
req, struct np_sock_connect_state);
|
||||
enum ndr_err_code ndr_err;
|
||||
int ret, err;
|
||||
|
||||
SMB_ASSERT(subreq == state->subreq);
|
||||
|
||||
ret = async_connect_recv(subreq, &err);
|
||||
TALLOC_FREE(subreq);
|
||||
state->subreq = NULL;
|
||||
if (ret == -1) {
|
||||
DBG_DEBUG("async_connect_recv returned %s\n", strerror(err));
|
||||
tevent_req_error(req, err);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = tstream_bsd_existing_socket(
|
||||
state, state->sock, &state->transport);
|
||||
if (ret == -1) {
|
||||
err = errno;
|
||||
DBG_DEBUG("tstream_bsd_existing_socket failed: %s\n",
|
||||
strerror(err));
|
||||
tevent_req_error(req, err);
|
||||
return;
|
||||
}
|
||||
state->sock = -1;
|
||||
|
||||
ndr_err = ndr_push_struct_blob(
|
||||
&state->npa_blob,
|
||||
state,
|
||||
state->npa_req,
|
||||
(ndr_push_flags_fn_t)ndr_push_named_pipe_auth_req);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
DBG_DEBUG("ndr_push_struct_blob failed: %s\n",
|
||||
ndr_errstr(ndr_err));
|
||||
tevent_req_error(req, ndr_map_error2errno(ndr_err));
|
||||
return;
|
||||
}
|
||||
state->iov = (struct iovec) {
|
||||
.iov_base = state->npa_blob.data,
|
||||
.iov_len = state->npa_blob.length,
|
||||
};
|
||||
|
||||
subreq = tstream_writev_send(
|
||||
state, state->ev, state->transport, &state->iov, 1);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return;
|
||||
}
|
||||
tevent_req_set_callback(subreq, np_sock_connect_written, req);
|
||||
}
|
||||
|
||||
static void np_sock_connect_written(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct np_sock_connect_state *state = tevent_req_data(
|
||||
req, struct np_sock_connect_state);
|
||||
int ret, err;
|
||||
|
||||
ret = tstream_writev_recv(subreq, &err);
|
||||
TALLOC_FREE(subreq);
|
||||
if (ret == -1) {
|
||||
DBG_DEBUG("tstream_writev_recv returned %s\n", strerror(err));
|
||||
tevent_req_error(req, err);
|
||||
return;
|
||||
}
|
||||
|
||||
subreq = tstream_u32_read_send(
|
||||
state, state->ev, 0x00FFFFFF, state->transport);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return;
|
||||
}
|
||||
tevent_req_set_callback(subreq, np_sock_connect_read_done, req);
|
||||
}
|
||||
|
||||
static void np_sock_connect_read_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct np_sock_connect_state *state = tevent_req_data(
|
||||
req, struct np_sock_connect_state);
|
||||
DATA_BLOB in;
|
||||
int ret;
|
||||
enum ndr_err_code ndr_err;
|
||||
|
||||
ret = tstream_u32_read_recv(subreq, state, &in.data, &in.length);
|
||||
TALLOC_FREE(subreq);
|
||||
if (tevent_req_error(req, ret)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ndr_err = ndr_pull_struct_blob_all(
|
||||
&in,
|
||||
state->npa_rep,
|
||||
state->npa_rep,
|
||||
(ndr_pull_flags_fn_t)ndr_pull_named_pipe_auth_rep);
|
||||
if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
DBG_DEBUG("ndr_pull_named_pipe_auth_rep failed: %s\n",
|
||||
ndr_errstr(ndr_err));
|
||||
tevent_req_error(req, ndr_map_error2errno(ndr_err));
|
||||
return;
|
||||
}
|
||||
if (state->npa_rep->level != 5) {
|
||||
DBG_DEBUG("npa level = %"PRIu32", expected 5\n",
|
||||
state->npa_rep->level);
|
||||
tevent_req_error(req, EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = tstream_npa_existing_stream(
|
||||
state,
|
||||
&state->transport,
|
||||
state->npa_rep->info.info5.file_type,
|
||||
&state->npa_stream);
|
||||
if (ret == -1) {
|
||||
ret = errno;
|
||||
DBG_DEBUG("tstream_npa_existing_stream failed: %s\n",
|
||||
strerror(ret));
|
||||
tevent_req_error(req, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
static int np_sock_connect_recv(
|
||||
struct tevent_req *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tstream_context **stream)
|
||||
{
|
||||
struct np_sock_connect_state *state = tevent_req_data(
|
||||
req, struct np_sock_connect_state);
|
||||
int err;
|
||||
|
||||
if (tevent_req_is_unix_error(req, &err)) {
|
||||
tevent_req_received(req);
|
||||
return err;
|
||||
}
|
||||
*stream = talloc_move(mem_ctx, &state->npa_stream);
|
||||
tevent_req_received(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct start_rpc_host_state {
|
||||
int ready_fd;
|
||||
struct tevent_req *read_ready_req;
|
||||
};
|
||||
|
||||
static void start_rpc_host_cleanup(
|
||||
struct tevent_req *req, enum tevent_req_state req_state);
|
||||
static void start_rpc_host_ready(struct tevent_req *subreq);
|
||||
|
||||
/*
|
||||
* Start samba-dcerpcd and wait for it to report ready.
|
||||
*/
|
||||
static struct tevent_req *start_rpc_host_send(
|
||||
TALLOC_CTX *mem_ctx, struct tevent_context *ev)
|
||||
{
|
||||
struct tevent_req *req = NULL, *subreq = NULL;
|
||||
struct start_rpc_host_state *state = NULL;
|
||||
int ret;
|
||||
int ready_fds[2] = { -1, -1 };
|
||||
char **argv = NULL;
|
||||
pid_t pid;
|
||||
bool ok;
|
||||
|
||||
req = tevent_req_create(
|
||||
mem_ctx, &state, struct start_rpc_host_state);
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = pipe(ready_fds);
|
||||
if (ret == -1) {
|
||||
ret = errno;
|
||||
DBG_DEBUG("pipe() failed: %s\n", strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ok = smb_set_close_on_exec(ready_fds[0]);
|
||||
if (!ok) {
|
||||
ret = errno;
|
||||
DBG_DEBUG("smb_set_close_on_exec failed: %s\n",
|
||||
strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
argv = str_list_make_empty(mem_ctx);
|
||||
str_list_add_printf(
|
||||
&argv, "%s/samba-dcerpcd", get_dyn_SAMBA_LIBEXECDIR());
|
||||
if (!is_default_dyn_CONFIGFILE()) {
|
||||
str_list_add_printf(
|
||||
&argv, "--configfile=%s", get_dyn_CONFIGFILE());
|
||||
}
|
||||
str_list_add_printf(&argv, "--libexec-rpcds");
|
||||
str_list_add_printf(&argv, "--ready-signal-fd=%d", ready_fds[1]);
|
||||
str_list_add_printf(&argv, "--np-helper");
|
||||
str_list_add_printf(
|
||||
&argv, "--debuglevel=%d", debuglevel_get_class(DBGC_RPC_SRV));
|
||||
if (!is_default_dyn_LOGFILEBASE()) {
|
||||
str_list_add_printf(
|
||||
&argv, "--log-basename=%s", get_dyn_LOGFILEBASE());
|
||||
}
|
||||
if (argv == NULL) {
|
||||
errno = ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
become_root();
|
||||
ret = posix_spawn(&pid, argv[0], NULL, NULL, argv, environ);
|
||||
unbecome_root();
|
||||
if (ret != 0) {
|
||||
DBG_DEBUG("posix_spawn() failed: %s\n", strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
state->ready_fd = ready_fds[0];
|
||||
ready_fds[0] = -1;
|
||||
tevent_req_set_cleanup_fn(req, start_rpc_host_cleanup);
|
||||
|
||||
close(ready_fds[1]);
|
||||
ready_fds[1] = -1;
|
||||
|
||||
subreq = read_packet_send(state, ev, state->ready_fd, 1, NULL, NULL);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
tevent_req_set_callback(subreq, start_rpc_host_ready, req);
|
||||
return req;
|
||||
|
||||
fail:
|
||||
if (ready_fds[0] == -1) {
|
||||
close(ready_fds[0]);
|
||||
ready_fds[0] = -1;
|
||||
}
|
||||
if (ready_fds[1] == -1) {
|
||||
close(ready_fds[1]);
|
||||
ready_fds[1] = -1;
|
||||
}
|
||||
tevent_req_error(req, ret);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
static void start_rpc_host_cleanup(
|
||||
struct tevent_req *req, enum tevent_req_state req_state)
|
||||
{
|
||||
struct start_rpc_host_state *state = tevent_req_data(
|
||||
req, struct start_rpc_host_state);
|
||||
|
||||
if (state->ready_fd != -1) {
|
||||
close(state->ready_fd);
|
||||
state->ready_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void start_rpc_host_ready(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct start_rpc_host_state *state = tevent_req_data(
|
||||
req, struct start_rpc_host_state);
|
||||
uint8_t *buf;
|
||||
int err;
|
||||
ssize_t nread;
|
||||
|
||||
nread = read_packet_recv(subreq, state, &buf, &err);
|
||||
TALLOC_FREE(subreq);
|
||||
if (nread == -1) {
|
||||
tevent_req_error(req, err);
|
||||
return;
|
||||
}
|
||||
|
||||
close(state->ready_fd);
|
||||
state->ready_fd = -1;
|
||||
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
static int start_rpc_host_recv(struct tevent_req *req)
|
||||
{
|
||||
return tevent_req_simple_recv_unix(req);
|
||||
}
|
||||
|
||||
struct local_np_connect_state {
|
||||
struct tevent_context *ev;
|
||||
const char *socketpath;
|
||||
struct named_pipe_auth_req *npa_req;
|
||||
struct tstream_context *npa_stream;
|
||||
};
|
||||
|
||||
static void local_np_connect_connected(struct tevent_req *subreq);
|
||||
static void local_np_connect_started(struct tevent_req *subreq);
|
||||
static void local_np_connect_retried(struct tevent_req *subreq);
|
||||
|
||||
/**
|
||||
* @brief Async connect to a local named pipe RPC interface
|
||||
*
|
||||
* Start "samba-dcerpcd" on demand if it does not exist
|
||||
*
|
||||
* @param[in] mem_ctx The memory context to use.
|
||||
* @param[in] ev The tevent context to use.
|
||||
*
|
||||
* @param[in] pipename The raw pipename to connect to without path
|
||||
* @param[in] remote_client_name The client name to transmit
|
||||
* @param[in] remote_client_addr The client addr to transmit
|
||||
* @param[in] local_server_name The server name to transmit
|
||||
* @param[in] local_server_addr The server addr to transmit
|
||||
* @param[in] session_info The authorization info to use
|
||||
* @param[in] need_idle_server Does this need to be an exclusive server?
|
||||
* @return The tevent_req that was started
|
||||
*/
|
||||
|
||||
struct tevent_req *local_np_connect_send(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
const char *pipename,
|
||||
enum dcerpc_transport_t transport,
|
||||
const char *remote_client_name,
|
||||
const struct tsocket_address *remote_client_addr,
|
||||
const char *local_server_name,
|
||||
const struct tsocket_address *local_server_addr,
|
||||
const struct auth_session_info *session_info,
|
||||
bool need_idle_server)
|
||||
{
|
||||
struct tevent_req *req = NULL, *subreq = NULL;
|
||||
struct local_np_connect_state *state = NULL;
|
||||
struct named_pipe_auth_req_info5 *i5 = NULL;
|
||||
const char *socket_dir = NULL;
|
||||
char *lower_case_pipename = NULL;
|
||||
|
||||
req = tevent_req_create(
|
||||
mem_ctx, &state, struct local_np_connect_state);
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
state->ev = ev;
|
||||
|
||||
socket_dir = lp_parm_const_string(
|
||||
GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
|
||||
lp_ncalrpc_dir());
|
||||
if (socket_dir == NULL) {
|
||||
DBG_DEBUG("external_rpc_pipe:socket_dir not set\n");
|
||||
tevent_req_error(req, EINVAL);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
lower_case_pipename = strlower_talloc(state, pipename);
|
||||
if (tevent_req_nomem(lower_case_pipename, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
state->socketpath = talloc_asprintf(
|
||||
state, "%s/np/%s", socket_dir, lower_case_pipename);
|
||||
if (tevent_req_nomem(state->socketpath, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
TALLOC_FREE(lower_case_pipename);
|
||||
|
||||
state->npa_req = talloc_zero(state, struct named_pipe_auth_req);
|
||||
if (tevent_req_nomem(state->npa_req, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
state->npa_req->level = 5;
|
||||
|
||||
i5 = &state->npa_req->info.info5;
|
||||
|
||||
i5->transport = transport;
|
||||
|
||||
/* we don't have "int" in IDL, make sure we don't overflow */
|
||||
SMB_ASSERT(i5->transport == transport);
|
||||
|
||||
if (remote_client_name == NULL) {
|
||||
remote_client_name = get_myname(state->npa_req);
|
||||
if (remote_client_name == NULL) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
}
|
||||
i5->remote_client_name = remote_client_name;
|
||||
|
||||
if (remote_client_addr == NULL) {
|
||||
struct tsocket_address *addr = NULL;
|
||||
int ret = tsocket_address_inet_from_strings(
|
||||
state->npa_req, "ip", NULL, 0, &addr);
|
||||
if (ret != 0) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
remote_client_addr = addr;
|
||||
}
|
||||
i5->remote_client_addr = tsocket_address_inet_addr_string(
|
||||
remote_client_addr, state->npa_req);
|
||||
if (i5->remote_client_addr == NULL) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
i5->remote_client_port = tsocket_address_inet_port(remote_client_addr);
|
||||
|
||||
if (local_server_name == NULL) {
|
||||
local_server_name = remote_client_name;
|
||||
}
|
||||
i5->local_server_name = local_server_name;
|
||||
|
||||
if (local_server_addr == NULL) {
|
||||
struct tsocket_address *addr = NULL;
|
||||
int ret = tsocket_address_inet_from_strings(
|
||||
state->npa_req, "ip", NULL, 0, &addr);
|
||||
if (ret != 0) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
local_server_addr = addr;
|
||||
}
|
||||
i5->local_server_addr = tsocket_address_inet_addr_string(
|
||||
local_server_addr, state->npa_req);
|
||||
if (i5->local_server_addr == NULL) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
i5->local_server_port = tsocket_address_inet_port(local_server_addr);
|
||||
|
||||
i5->session_info = talloc_zero(
|
||||
state->npa_req, struct auth_session_info_transport);
|
||||
if (tevent_req_nomem(i5->session_info, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
i5->session_info->session_info = copy_session_info(
|
||||
i5->session_info, session_info);
|
||||
if (tevent_req_nomem(i5->session_info->session_info, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
i5->need_idle_server = need_idle_server;
|
||||
|
||||
subreq = np_sock_connect_send(
|
||||
state, state->ev, state->socketpath, state->npa_req);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
tevent_req_set_callback(subreq, local_np_connect_connected, req);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void local_np_connect_connected(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct local_np_connect_state *state = tevent_req_data(
|
||||
req, struct local_np_connect_state);
|
||||
int ret;
|
||||
|
||||
ret = np_sock_connect_recv(subreq, state, &state->npa_stream);
|
||||
TALLOC_FREE(subreq);
|
||||
|
||||
if (ret == 0) {
|
||||
tevent_req_done(req);
|
||||
return;
|
||||
}
|
||||
|
||||
DBG_DEBUG("np_sock_connect failed: %s\n", strerror(ret));
|
||||
|
||||
if (!lp_rpc_start_on_demand_helpers()) {
|
||||
/*
|
||||
* samba-dcerpcd should already be started in
|
||||
* daemon/standalone mode when "rpc start on demand
|
||||
* helpers = false". We are prohibited from starting
|
||||
* on demand as a named-pipe helper.
|
||||
*/
|
||||
DBG_ERR("Can't connect to a running samba-dcerpcd. smb.conf "
|
||||
"config prohibits starting as named pipe helper as "
|
||||
"the [global] section contains "
|
||||
"\"rpc start on demand helpers = false\".\n");
|
||||
tevent_req_error(req, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* samba-dcerpcd isn't running. We need to start it.
|
||||
* Note if it doesn't start we treat this as a fatal
|
||||
* error for connecting to the named pipe and don't
|
||||
* keep trying to restart for this connection.
|
||||
*/
|
||||
subreq = start_rpc_host_send(state, state->ev);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return;
|
||||
}
|
||||
tevent_req_set_callback(subreq, local_np_connect_started, req);
|
||||
}
|
||||
|
||||
static void local_np_connect_started(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct local_np_connect_state *state = tevent_req_data(
|
||||
req, struct local_np_connect_state);
|
||||
int ret;
|
||||
|
||||
ret = start_rpc_host_recv(subreq);
|
||||
TALLOC_FREE(subreq);
|
||||
if (tevent_req_error(req, ret)) {
|
||||
DBG_DEBUG("start_rpc_host_recv failed: %s\n",
|
||||
strerror(ret));
|
||||
return;
|
||||
}
|
||||
|
||||
subreq = np_sock_connect_send(
|
||||
state, state->ev, state->socketpath, state->npa_req);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return;
|
||||
}
|
||||
tevent_req_set_callback(subreq, local_np_connect_retried, req);
|
||||
}
|
||||
|
||||
static void local_np_connect_retried(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct local_np_connect_state *state = tevent_req_data(
|
||||
req, struct local_np_connect_state);
|
||||
int ret;
|
||||
|
||||
ret = np_sock_connect_recv(subreq, state, &state->npa_stream);
|
||||
TALLOC_FREE(subreq);
|
||||
if (tevent_req_error(req, ret)) {
|
||||
return;
|
||||
}
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Receive handle to a local named pipe RPC interface
|
||||
*
|
||||
* @param[in] req The tevent_req that started the operation
|
||||
* @param[in] ev The tevent context to use.
|
||||
* @param[in] mem_ctx The memory context to put pstream on
|
||||
* @param[out] pstream The established connection to the RPC server
|
||||
*
|
||||
* @return 0/errno
|
||||
*/
|
||||
|
||||
int local_np_connect_recv(
|
||||
struct tevent_req *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tstream_context **pstream)
|
||||
{
|
||||
struct local_np_connect_state *state = tevent_req_data(
|
||||
req, struct local_np_connect_state);
|
||||
int err;
|
||||
|
||||
if (tevent_req_is_unix_error(req, &err)) {
|
||||
tevent_req_received(req);
|
||||
return err;
|
||||
}
|
||||
|
||||
*pstream = talloc_move(mem_ctx, &state->npa_stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sync connect to a local named pipe RPC interface
|
||||
*
|
||||
* Start "samba-dcerpcd" on demand if it does not exist
|
||||
*
|
||||
* @param[in] pipename The raw pipename to connect to without path
|
||||
* @param[in] remote_client_name The client name to transmit
|
||||
* @param[in] remote_client_addr The client addr to transmit
|
||||
* @param[in] local_server_name The server name to transmit
|
||||
* @param[in] local_server_addr The server addr to transmit
|
||||
* @param[in] session_info The authorization info to use
|
||||
* @param[in] need_idle_server Does this need to be an exclusive server?
|
||||
* @param[in] mem_ctx The memory context to use.
|
||||
* @param[out] pstream The established connection to the RPC server
|
||||
* @return 0/errno
|
||||
*/
|
||||
|
||||
int local_np_connect(
|
||||
const char *pipename,
|
||||
enum dcerpc_transport_t transport,
|
||||
const char *remote_client_name,
|
||||
const struct tsocket_address *remote_client_addr,
|
||||
const char *local_server_name,
|
||||
const struct tsocket_address *local_server_addr,
|
||||
const struct auth_session_info *session_info,
|
||||
bool need_idle_server,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tstream_context **pstream)
|
||||
{
|
||||
struct tevent_context *ev = NULL;
|
||||
struct tevent_req *req = NULL;
|
||||
int ret = ENOMEM;
|
||||
|
||||
ev = samba_tevent_context_init(mem_ctx);
|
||||
if (ev == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
req = local_np_connect_send(
|
||||
ev,
|
||||
ev,
|
||||
pipename,
|
||||
transport,
|
||||
remote_client_name,
|
||||
remote_client_addr,
|
||||
local_server_name,
|
||||
local_server_addr,
|
||||
session_info,
|
||||
need_idle_server);
|
||||
if (req == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
if (!tevent_req_poll_unix(req, ev, &ret)) {
|
||||
goto fail;
|
||||
}
|
||||
ret = local_np_connect_recv(req, mem_ctx, pstream);
|
||||
fail:
|
||||
TALLOC_FREE(req);
|
||||
TALLOC_FREE(ev);
|
||||
return ret;
|
||||
}
|
56
source3/rpc_client/local_np.h
Normal file
56
source3/rpc_client/local_np.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Unix SMB/CIFS implementation.
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _LOCAL_NP_H_
|
||||
#define _LOCAL_NP_H_
|
||||
|
||||
#include <replace.h>
|
||||
#include "lib/tsocket/tsocket.h"
|
||||
#include "librpc/rpc/rpc_common.h"
|
||||
|
||||
struct auth_session_info;
|
||||
|
||||
struct tevent_req *local_np_connect_send(
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
const char *pipename,
|
||||
enum dcerpc_transport_t transport,
|
||||
const char *remote_client_name,
|
||||
const struct tsocket_address *remote_client_addr,
|
||||
const char *local_server_name,
|
||||
const struct tsocket_address *local_server_addr,
|
||||
const struct auth_session_info *session_info,
|
||||
bool need_idle_server);
|
||||
|
||||
int local_np_connect_recv(
|
||||
struct tevent_req *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tstream_context **pstream);
|
||||
|
||||
int local_np_connect(
|
||||
const char *pipename,
|
||||
enum dcerpc_transport_t transport,
|
||||
const char *remote_client_name,
|
||||
const struct tsocket_address *remote_client_addr,
|
||||
const char *local_server_name,
|
||||
const struct tsocket_address *local_server_addr,
|
||||
const struct auth_session_info *session_info,
|
||||
bool need_idle_server,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct tstream_context **stream);
|
||||
|
||||
#endif /* _LOCAL_NP_H_ */
|
@ -55,6 +55,7 @@ bld.SAMBA3_LIBRARY('msrpc3',
|
||||
rpc_client/rpc_transport_np.c
|
||||
rpc_client/rpc_transport_sock.c
|
||||
rpc_client/rpc_transport_tstream.c
|
||||
rpc_client/local_np.c
|
||||
librpc/rpc/dcerpc_helpers.c
|
||||
''',
|
||||
deps='''
|
||||
@ -65,6 +66,7 @@ bld.SAMBA3_LIBRARY('msrpc3',
|
||||
COMMON_SCHANNEL
|
||||
LIBCLI_AUTH
|
||||
LIBTSOCKET
|
||||
npa_tstream
|
||||
gse
|
||||
dcerpc-binding
|
||||
libsmb
|
||||
|
Loading…
Reference in New Issue
Block a user