mirror of
https://github.com/samba-team/samba.git
synced 2025-01-10 01:18:15 +03:00
s3:rpc_server: Improve local dispatching
Craft core structures to dispatch local calls in the same way as remote ones, removing the special handling in the autogenerated code. This is also necessary to drop s3 rpc handles implementation. Signed-off-by: Samuel Cabrero <scabrero@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org> Autobuild-User(master): Andrew Bartlett <abartlet@samba.org> Autobuild-Date(master): Wed Apr 8 22:23:05 UTC 2020 on sn-devel-184
This commit is contained in:
parent
bce570cfd7
commit
03f79a3bd7
@ -69,7 +69,7 @@ struct dcesrv_interface {
|
||||
|
||||
/* the local dispatch function for the chosen interface.
|
||||
*/
|
||||
NTSTATUS (*local)(void *p, int opnum, TALLOC_CTX *, const DATA_BLOB *in, DATA_BLOB *out);
|
||||
NTSTATUS (*local)(struct dcesrv_call_state *, TALLOC_CTX *, void *);
|
||||
|
||||
/* for any private use by the interface code */
|
||||
const void *private_data;
|
||||
|
@ -212,67 +212,6 @@ sub gen_reply_switch($)
|
||||
}
|
||||
}
|
||||
|
||||
# generate the switch statement for local function dispatch
|
||||
sub gen_local_dispatch_switch($)
|
||||
{
|
||||
my ($self, $interface) = @_;
|
||||
|
||||
my @alloc_error_block = ("p->fault_state = DCERPC_FAULT_CANT_PERFORM;",
|
||||
"return NT_STATUS_NO_MEMORY;");
|
||||
|
||||
foreach my $fn (@{$interface->{FUNCTIONS}}) {
|
||||
next if not defined($fn->{OPNUM});
|
||||
|
||||
$self->pidl("case $fn->{OPNUM}: { /* $fn->{NAME} */");
|
||||
$self->indent();
|
||||
$self->pidl("struct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;");
|
||||
$self->pidl("if (DEBUGLEVEL >= 10) {\n");
|
||||
$self->indent();
|
||||
$self->pidl("NDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_IN, r2);");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
|
||||
$self->gen_fn_out($fn, \@alloc_error_block);
|
||||
|
||||
if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
|
||||
$self->pidl("r2->out.result = _$fn->{NAME}(p, r2);");
|
||||
} else {
|
||||
$self->pidl("_$fn->{NAME}(p, r2);");
|
||||
}
|
||||
$self->pidl("break;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################
|
||||
# generate the switch statement for local function reply
|
||||
sub gen_local_reply_switch($)
|
||||
{
|
||||
my ($self, $interface) = @_;
|
||||
|
||||
foreach my $fn (@{$interface->{FUNCTIONS}}) {
|
||||
next if not defined($fn->{OPNUM});
|
||||
|
||||
$self->pidl("case $fn->{OPNUM}: { /* $fn->{NAME} */");
|
||||
$self->indent();
|
||||
$self->pidl("struct $fn->{NAME} *r2 = (struct $fn->{NAME} *)r;");
|
||||
$self->pidl("if (DEBUGLEVEL >= 10 && p->fault_state == 0) {");
|
||||
$self->indent();
|
||||
$self->pidl("NDR_PRINT_FUNCTION_DEBUG($fn->{NAME}, NDR_OUT | NDR_SET_VALUES, r2);");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("if (p->fault_state != 0) {\n");
|
||||
$self->indent();
|
||||
$self->pidl("DBG_WARNING(\"dcerpc_fault %s in $fn->{NAME}\\n\", dcerpc_errstr(mem_ctx, p->fault_state));");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("break;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
}
|
||||
}
|
||||
|
||||
#####################################################################
|
||||
# produce boilerplate code for a interface
|
||||
sub boilerplate_iface($)
|
||||
@ -392,15 +331,14 @@ sub boilerplate_iface($)
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
|
||||
$self->pidl_hdr("NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r);");
|
||||
$self->pidl("NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)");
|
||||
$self->pidl("static NTSTATUS $name\__op_dispatch_internal(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r, enum s3compat_rpc_dispatch dispatch)");
|
||||
$self->pidl("{");
|
||||
$self->indent();
|
||||
$self->pidl("uint16_t opnum = dce_call->pkt.u.request.opnum;");
|
||||
$self->pidl("struct pipes_struct *p = NULL;");
|
||||
$self->pidl("struct auth_session_info *pipe_session_info = NULL;");
|
||||
$self->pidl("NTSTATUS status = NT_STATUS_OK;");
|
||||
$self->pidl("bool impersonated;");
|
||||
$self->pidl("bool impersonated = false;");
|
||||
$self->pidl("");
|
||||
$self->pidl("/* Retrieve pipes struct */");
|
||||
$self->pidl("p = dcesrv_get_pipes_struct(dce_call->conn);");
|
||||
@ -417,6 +355,8 @@ sub boilerplate_iface($)
|
||||
$self->pidl("");
|
||||
|
||||
$self->pidl("/* Impersonate */");
|
||||
$self->pidl("if (dispatch == S3COMPAT_RPC_DISPATCH_EXTERNAL) {");
|
||||
$self->indent();
|
||||
$self->pidl("impersonated = become_authenticated_pipe_user(p->session_info);");
|
||||
$self->pidl("if (!impersonated) {");
|
||||
$self->indent();
|
||||
@ -425,6 +365,8 @@ sub boilerplate_iface($)
|
||||
$self->pidl("goto fail;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
|
||||
$self->pidl("switch (opnum) {");
|
||||
@ -469,6 +411,15 @@ sub boilerplate_iface($)
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
|
||||
$self->pidl_hdr("NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r);");
|
||||
$self->pidl("NTSTATUS $name\__op_dispatch(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)");
|
||||
$self->pidl("{");
|
||||
$self->indent();
|
||||
$self->pidl("return $name\__op_dispatch_internal(dce_call, mem_ctx, r, S3COMPAT_RPC_DISPATCH_EXTERNAL);");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
|
||||
$self->pidl_hdr("NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r);");
|
||||
$self->pidl("NTSTATUS $name\__op_reply(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)");
|
||||
$self->pidl("{");
|
||||
@ -519,112 +470,11 @@ sub boilerplate_iface($)
|
||||
##############################
|
||||
#### LOCAL DISPATCH ####
|
||||
##############################
|
||||
$self->pidl_hdr("NTSTATUS $name\__op_local(void *q, int opnum, TALLOC_CTX *mem_ctx, const DATA_BLOB *in, DATA_BLOB *out);");
|
||||
$self->pidl("NTSTATUS $name\__op_local(void *q, int opnum, TALLOC_CTX *mem_ctx, const DATA_BLOB *in, DATA_BLOB *out)");
|
||||
$self->pidl_hdr("NTSTATUS $name\__op_local(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r);");
|
||||
$self->pidl("NTSTATUS $name\__op_local(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, void *r)");
|
||||
$self->pidl("{");
|
||||
$self->indent();
|
||||
$self->pidl("struct pipes_struct *p = talloc_get_type_abort(q, struct pipes_struct);");
|
||||
$self->pidl("void *r;");
|
||||
$self->pidl("struct ndr_pull *pull;");
|
||||
$self->pidl("struct ndr_push *push;");
|
||||
$self->pidl("enum ndr_err_code ndr_err;");
|
||||
$self->pidl("");
|
||||
$self->pidl("p->fault_state = 0;");
|
||||
$self->pidl("if (opnum >= ndr_table_$name.num_calls) {");
|
||||
$self->indent();
|
||||
$self->pidl("p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;");
|
||||
$self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("r = talloc_named(mem_ctx, ndr_table_$name.calls[opnum].struct_size, \"struct %s\", ndr_table_$name.calls[opnum].name);");
|
||||
$self->pidl("if (r == NULL) {");
|
||||
$self->indent();
|
||||
$self->pidl("p->fault_state = DCERPC_FAULT_CANT_PERFORM;");
|
||||
$self->pidl("return NT_STATUS_NO_MEMORY;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("pull = ndr_pull_init_blob(in, r);");
|
||||
$self->pidl("if (pull == NULL) {");
|
||||
$self->indent();
|
||||
$self->pidl("talloc_free(r);");
|
||||
$self->pidl("p->fault_state = DCERPC_FAULT_CANT_PERFORM;");
|
||||
$self->pidl("return NT_STATUS_NO_MEMORY;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("pull->flags |= LIBNDR_FLAG_REF_ALLOC;");
|
||||
$self->pidl("if (p->endian) {");
|
||||
$self->indent();
|
||||
$self->pidl("pull->flags |= LIBNDR_FLAG_BIGENDIAN;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("ndr_err = ndr_table_$name.calls[opnum].ndr_pull(pull, NDR_IN, r);");
|
||||
$self->pidl("if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {");
|
||||
$self->indent();
|
||||
$self->pidl("p->fault_state = DCERPC_FAULT_NDR;");
|
||||
$self->pidl("talloc_free(r);");
|
||||
$self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("switch (opnum) {");
|
||||
$self->gen_local_dispatch_switch($interface);
|
||||
$self->pidl("default:");
|
||||
$self->indent();
|
||||
$self->pidl("p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;");
|
||||
$self->pidl("break;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("if (p->fault_state != 0) {");
|
||||
$self->indent();
|
||||
$self->pidl("talloc_free(r);");
|
||||
$self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("switch (opnum) {");
|
||||
$self->gen_local_reply_switch($interface);
|
||||
$self->pidl("default:");
|
||||
$self->indent();
|
||||
$self->pidl("p->fault_state = DCERPC_FAULT_OP_RNG_ERROR;");
|
||||
$self->pidl("break;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("push = ndr_push_init_ctx(r);");
|
||||
$self->pidl("if (push == NULL) {");
|
||||
$self->indent();
|
||||
$self->pidl("talloc_free(r);");
|
||||
$self->pidl("p->fault_state = DCERPC_FAULT_CANT_PERFORM;");
|
||||
$self->pidl("return NT_STATUS_NO_MEMORY;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("/*");
|
||||
$self->pidl(" * carry over the pointer count to the reply in case we are");
|
||||
$self->pidl(" * using full pointer. See NDR specification for full pointers");
|
||||
$self->pidl(" */");
|
||||
$self->pidl("push->ptr_count = pull->ptr_count;");
|
||||
$self->pidl("");
|
||||
$self->pidl("ndr_err = ndr_table_$name.calls[opnum].ndr_push(push, NDR_OUT, r);");
|
||||
$self->pidl("if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {");
|
||||
$self->indent();
|
||||
$self->pidl("p->fault_state = DCERPC_FAULT_NDR;");
|
||||
$self->pidl("talloc_free(r);");
|
||||
$self->pidl("return NT_STATUS_NET_WRITE_FAULT;");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
$self->pidl("*out = ndr_push_blob(push);");
|
||||
$self->pidl("talloc_steal(mem_ctx, out->data);");
|
||||
$self->pidl("");
|
||||
$self->pidl("talloc_free(r);");
|
||||
$self->pidl("");
|
||||
$self->pidl("return NT_STATUS_OK;");
|
||||
$self->pidl("return $name\__op_dispatch_internal(dce_call, mem_ctx, r, S3COMPAT_RPC_DISPATCH_INTERNAL);");
|
||||
$self->deindent();
|
||||
$self->pidl("}");
|
||||
$self->pidl("");
|
||||
@ -854,6 +704,13 @@ sub Parse($$)
|
||||
$self->pidl("#include <rpc_server/rpc_server.h>");
|
||||
$self->pidl("#include <util/debug.h>");
|
||||
$self->pidl("");
|
||||
$self->pidl("enum s3compat_rpc_dispatch {");
|
||||
$self->indent();
|
||||
$self->pidl("S3COMPAT_RPC_DISPATCH_EXTERNAL = 0x00000001,");
|
||||
$self->pidl("S3COMPAT_RPC_DISPATCH_INTERNAL = 0x00000002,");
|
||||
$self->deindent();
|
||||
$self->pidl("};");
|
||||
$self->pidl("");
|
||||
|
||||
foreach my $x (@{$ndr}) {
|
||||
$self->parse_interface($x) if ($x->{TYPE} eq "INTERFACE" and not defined($x->{PROPERTIES}{object}));
|
||||
|
@ -42,14 +42,6 @@
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_RPC_SRV
|
||||
|
||||
static NTSTATUS make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
|
||||
const struct ndr_syntax_id *syntax,
|
||||
const struct tsocket_address *remote_address,
|
||||
const struct tsocket_address *local_address,
|
||||
const struct auth_session_info *session_info,
|
||||
struct messaging_context *msg_ctx,
|
||||
struct pipes_struct **p);
|
||||
|
||||
struct np_proxy_state {
|
||||
uint16_t file_type;
|
||||
uint16_t device_state;
|
||||
@ -249,118 +241,274 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Make an internal namedpipes structure
|
||||
****************************************************************************/
|
||||
|
||||
static NTSTATUS make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx,
|
||||
const struct ndr_syntax_id *syntax,
|
||||
static NTSTATUS make_internal_ncacn_conn(TALLOC_CTX *mem_ctx,
|
||||
const struct ndr_interface_table *table,
|
||||
const struct tsocket_address *remote_address,
|
||||
const struct tsocket_address *local_address,
|
||||
const struct auth_session_info *session_info,
|
||||
struct messaging_context *msg_ctx,
|
||||
struct pipes_struct **p)
|
||||
struct dcerpc_ncacn_conn **_out)
|
||||
{
|
||||
struct pipes_struct *out;
|
||||
struct pipe_rpc_fns *context_fns;
|
||||
const char *pipe_name;
|
||||
struct dcerpc_ncacn_conn *ncacn_conn = NULL;
|
||||
const char *pipe_name = NULL;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
const struct ndr_interface_table *table;
|
||||
|
||||
table = ndr_table_by_uuid(&syntax->uuid);
|
||||
if (table == NULL) {
|
||||
DBG_ERR("Unknown interface\n");
|
||||
return NT_STATUS_RPC_INTERFACE_NOT_FOUND;
|
||||
}
|
||||
|
||||
pipe_name = dcerpc_default_transport_endpoint(mem_ctx, NCACN_NP, table);
|
||||
pipe_name = dcerpc_default_transport_endpoint(mem_ctx,
|
||||
NCACN_NP,
|
||||
table);
|
||||
|
||||
DBG_INFO("Create pipe requested %s\n", pipe_name);
|
||||
|
||||
ret = make_base_pipes_struct(mem_ctx, msg_ctx, pipe_name,
|
||||
NCALRPC, RPC_LITTLE_ENDIAN,
|
||||
remote_address, local_address, &out);
|
||||
ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
|
||||
if (ncacn_conn == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ncacn_conn->msg_ctx = msg_ctx;
|
||||
|
||||
if (remote_address != NULL) {
|
||||
ncacn_conn->remote_client_addr =
|
||||
tsocket_address_copy(remote_address, ncacn_conn);
|
||||
if (ncacn_conn->remote_client_addr == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (local_address != NULL) {
|
||||
ncacn_conn->local_server_addr =
|
||||
tsocket_address_copy(local_address, ncacn_conn);
|
||||
if (ncacn_conn->local_server_addr == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
ncacn_conn->session_info = copy_session_info(ncacn_conn, session_info);
|
||||
if (ncacn_conn->session_info == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = make_base_pipes_struct(ncacn_conn,
|
||||
msg_ctx,
|
||||
pipe_name,
|
||||
NCALRPC,
|
||||
RPC_LITTLE_ENDIAN,
|
||||
ncacn_conn->remote_client_addr,
|
||||
ncacn_conn->local_server_addr,
|
||||
&ncacn_conn->p);
|
||||
if (ret) {
|
||||
DBG_ERR("No memory for pipes_struct!\n");
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!init_pipe_handles(out, syntax)) {
|
||||
if (!init_pipe_handles(ncacn_conn->p, &table->syntax_id)) {
|
||||
DBG_ERR("init_pipe_handles failed.\n");
|
||||
TALLOC_FREE(out);
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
status = NT_STATUS_UNSUCCESSFUL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
out->session_info = copy_session_info(out, session_info);
|
||||
if (out->session_info == NULL) {
|
||||
DBG_ERR("copy_serverinfo failed\n");
|
||||
close_policy_by_pipe(out);
|
||||
TALLOC_FREE(out);
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
context_fns = talloc_zero(out, struct pipe_rpc_fns);
|
||||
context_fns = talloc_zero(ncacn_conn->p, struct pipe_rpc_fns);
|
||||
if (context_fns == NULL) {
|
||||
DBG_ERR("No memory");
|
||||
TALLOC_FREE(out);
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
context_fns->next = context_fns->prev = NULL;
|
||||
context_fns->context_id = 0;
|
||||
context_fns->syntax = *syntax;
|
||||
context_fns->syntax = table->syntax_id;
|
||||
|
||||
/* add to the list of open contexts */
|
||||
DLIST_ADD(out->contexts, context_fns);
|
||||
DLIST_ADD(ncacn_conn->p->contexts, context_fns);
|
||||
|
||||
DEBUG(4,("Created internal pipe %s\n", pipe_name));
|
||||
|
||||
*p = out;
|
||||
*_out = ncacn_conn;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
|
||||
fail:
|
||||
talloc_free(ncacn_conn);
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS rpcint_dispatch(struct pipes_struct *p,
|
||||
static NTSTATUS find_ncalrpc_default_endpoint(struct dcesrv_context *dce_ctx,
|
||||
struct dcesrv_endpoint **ep)
|
||||
{
|
||||
TALLOC_CTX *tmp_ctx = NULL;
|
||||
struct dcerpc_binding *binding = NULL;
|
||||
const char *ep_description = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
tmp_ctx = talloc_new(dce_ctx);
|
||||
if (tmp_ctx == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some services use a rpcint binding handle in their initialization,
|
||||
* before the server is fully initialized. Search the NCALRPC endpoint
|
||||
* with and without endpoint
|
||||
*/
|
||||
status = dcerpc_parse_binding(tmp_ctx, "ncalrpc:", &binding);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = dcesrv_find_endpoint(dce_ctx, binding, ep);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
|
||||
ep_description = "ncalrpc:[SMBD]";
|
||||
} else {
|
||||
ep_description = "ncalrpc:[DEFAULT]";
|
||||
}
|
||||
|
||||
status = dcerpc_parse_binding(tmp_ctx, ep_description, &binding);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = dcesrv_find_endpoint(dce_ctx, binding, ep);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
talloc_free(tmp_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS make_internal_dcesrv_connection(TALLOC_CTX *mem_ctx,
|
||||
const struct ndr_interface_table *ndr_table,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32_t opnum,
|
||||
const DATA_BLOB *in_data,
|
||||
DATA_BLOB *out_data)
|
||||
struct dcerpc_ncacn_conn *ncacn_conn,
|
||||
struct dcesrv_connection **_out)
|
||||
{
|
||||
struct dcesrv_connection *conn = NULL;
|
||||
struct dcesrv_connection_context *context = NULL;
|
||||
struct dcesrv_endpoint *endpoint = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
conn = talloc_zero(mem_ctx, struct dcesrv_connection);
|
||||
if (conn == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
conn->dce_ctx = global_dcesrv_context();
|
||||
conn->preferred_transfer = &ndr_transfer_syntax_ndr;
|
||||
conn->transport.private_data = ncacn_conn;
|
||||
|
||||
status = find_ncalrpc_default_endpoint(conn->dce_ctx, &endpoint);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
conn->endpoint = endpoint;
|
||||
|
||||
conn->default_auth_state = talloc_zero(conn, struct dcesrv_auth);
|
||||
if (conn->default_auth_state == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
conn->default_auth_state->session_info = ncacn_conn->session_info;
|
||||
conn->default_auth_state->auth_finished = true;
|
||||
|
||||
context = talloc_zero(conn, struct dcesrv_connection_context);
|
||||
if (context == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
context->conn = conn;
|
||||
context->context_id = 0;
|
||||
context->transfer_syntax = *(conn->preferred_transfer);
|
||||
context->iface = find_interface_by_uuid(conn->endpoint,
|
||||
&ndr_table->syntax_id.uuid,
|
||||
ndr_table->syntax_id.if_version);
|
||||
if (context->iface == NULL) {
|
||||
status = NT_STATUS_RPC_INTERFACE_NOT_FOUND;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DLIST_ADD(conn->contexts, context);
|
||||
|
||||
*_out = conn;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
fail:
|
||||
talloc_free(conn);
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS rpcint_dispatch(struct dcesrv_call_state *call)
|
||||
{
|
||||
NTSTATUS status;
|
||||
const struct dcesrv_endpoint_server *ep_server = NULL;
|
||||
struct dcesrv_interface iface;
|
||||
const struct ndr_syntax_id *abstract_syntax = &ndr_table->syntax_id;
|
||||
bool ok;
|
||||
struct ndr_pull *pull = NULL;
|
||||
struct ndr_push *push = NULL;
|
||||
struct data_blob_list_item *rep = NULL;
|
||||
|
||||
ep_server = dcesrv_ep_server_byname(ndr_table->name);
|
||||
if (ep_server == NULL) {
|
||||
DBG_ERR("Failed to get DCE/RPC endpoint server '%s'\n",
|
||||
ndr_table->name);
|
||||
return NT_STATUS_NOT_FOUND;
|
||||
pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier,
|
||||
call);
|
||||
if (pull == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ok = ep_server->interface_by_uuid(&iface, &abstract_syntax->uuid,
|
||||
abstract_syntax->if_version);
|
||||
if (!ok) {
|
||||
DBG_ERR("Failed to get DCE/RPC interface\n");
|
||||
return NT_STATUS_NOT_FOUND;
|
||||
}
|
||||
pull->flags |= LIBNDR_FLAG_REF_ALLOC;
|
||||
|
||||
status = iface.local(p, opnum, mem_ctx, in_data, out_data);
|
||||
call->ndr_pull = pull;
|
||||
|
||||
/* unravel the NDR for the packet */
|
||||
status = call->context->iface->ndr_pull(call, call, pull, &call->r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_ERR("DCE/RPC fault in call %s:%02X - %s\n",
|
||||
iface.name, opnum,
|
||||
dcerpc_errstr(mem_ctx, p->fault_state));
|
||||
call->context->iface->name,
|
||||
call->pkt.u.request.opnum,
|
||||
dcerpc_errstr(call, call->fault_code));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = call->context->iface->local(call, call, call->r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_ERR("DCE/RPC fault in call %s:%02X - %s\n",
|
||||
call->context->iface->name,
|
||||
call->pkt.u.request.opnum,
|
||||
dcerpc_errstr(call, call->fault_code));
|
||||
return status;
|
||||
}
|
||||
|
||||
push = ndr_push_init_ctx(call);
|
||||
if (push == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
push->ptr_count = call->ndr_pull->ptr_count;
|
||||
|
||||
status = call->context->iface->ndr_push(call, call, push, call->r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_ERR("DCE/RPC fault in call %s:%02X - %s\n",
|
||||
call->context->iface->name,
|
||||
call->pkt.u.request.opnum,
|
||||
dcerpc_errstr(call, call->fault_code));
|
||||
return status;
|
||||
}
|
||||
|
||||
rep = talloc_zero(call, struct data_blob_list_item);
|
||||
if (rep == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
rep->blob = ndr_push_blob(push);
|
||||
DLIST_ADD_END(call->replies, rep);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
struct rpcint_bh_state {
|
||||
struct pipes_struct *p;
|
||||
const struct ndr_interface_table *ndr_table;
|
||||
struct dcesrv_connection *conn;
|
||||
};
|
||||
|
||||
static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
|
||||
@ -368,7 +516,7 @@ static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
|
||||
struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
|
||||
struct rpcint_bh_state);
|
||||
|
||||
if (!hs->p) {
|
||||
if (hs->conn == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -383,9 +531,7 @@ static uint32_t rpcint_bh_set_timeout(struct dcerpc_binding_handle *h,
|
||||
}
|
||||
|
||||
struct rpcint_bh_raw_call_state {
|
||||
DATA_BLOB in_data;
|
||||
DATA_BLOB out_data;
|
||||
uint32_t out_flags;
|
||||
struct dcesrv_call_state *call;
|
||||
};
|
||||
|
||||
static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
|
||||
@ -402,6 +548,7 @@ static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
|
||||
struct rpcint_bh_state);
|
||||
struct tevent_req *req;
|
||||
struct rpcint_bh_raw_call_state *state;
|
||||
struct dcesrv_context *dce_ctx = global_dcesrv_context();
|
||||
bool ok;
|
||||
NTSTATUS status;
|
||||
|
||||
@ -410,8 +557,6 @@ static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
state->in_data.data = discard_const_p(uint8_t, in_data);
|
||||
state->in_data.length = in_length;
|
||||
|
||||
ok = rpcint_bh_is_connected(h);
|
||||
if (!ok) {
|
||||
@ -419,13 +564,33 @@ static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
state->call = talloc_zero(hs->conn, struct dcesrv_call_state);
|
||||
if (tevent_req_nomem(state->call, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
state->call->event_ctx = ev;
|
||||
state->call->conn = hs->conn;
|
||||
state->call->context = hs->conn->contexts;
|
||||
state->call->auth_state = hs->conn->default_auth_state;
|
||||
|
||||
if (hs->conn->assoc_group == NULL) {
|
||||
ZERO_STRUCT(state->call->pkt);
|
||||
state->call->pkt.u.bind.assoc_group_id = 0;
|
||||
status = dce_ctx->callbacks.assoc_group.find(state->call);
|
||||
if (tevent_req_nterror(req, status)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
}
|
||||
|
||||
ZERO_STRUCT(state->call->pkt);
|
||||
state->call->pkt.u.request.opnum = opnum;
|
||||
state->call->pkt.u.request.context_id = 0;
|
||||
state->call->pkt.u.request.stub_and_verifier.data = discard_const_p(uint8_t, in_data);
|
||||
state->call->pkt.u.request.stub_and_verifier.length = in_length;
|
||||
|
||||
/* TODO: allow async */
|
||||
status = rpcint_dispatch(hs->p,
|
||||
hs->ndr_table,
|
||||
state,
|
||||
opnum,
|
||||
&state->in_data,
|
||||
&state->out_data);
|
||||
status = rpcint_dispatch(state->call);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
tevent_req_nterror(req, status);
|
||||
return tevent_req_post(req, ev);
|
||||
@ -444,6 +609,7 @@ static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
|
||||
struct rpcint_bh_raw_call_state *state =
|
||||
tevent_req_data(req,
|
||||
struct rpcint_bh_raw_call_state);
|
||||
struct data_blob_list_item *rep = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
if (tevent_req_is_nterror(req, &status)) {
|
||||
@ -451,9 +617,15 @@ static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
|
||||
return status;
|
||||
}
|
||||
|
||||
*out_data = talloc_move(mem_ctx, &state->out_data.data);
|
||||
*out_length = state->out_data.length;
|
||||
rep = state->call->replies;
|
||||
DLIST_REMOVE(state->call->replies, rep);
|
||||
|
||||
*out_data = talloc_steal(mem_ctx, rep->blob.data);
|
||||
*out_length = rep->blob.length;
|
||||
*out_flags = 0;
|
||||
|
||||
talloc_free(rep);
|
||||
|
||||
tevent_req_received(req);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
@ -487,9 +659,9 @@ static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
|
||||
/*
|
||||
* TODO: do a real async disconnect ...
|
||||
*
|
||||
* For now the caller needs to free pipes_struct
|
||||
* For now the caller needs to free dcesrv_connection
|
||||
*/
|
||||
hs->p = NULL;
|
||||
hs->conn = NULL;
|
||||
|
||||
tevent_req_done(req);
|
||||
return tevent_req_post(req, ev);
|
||||
@ -562,12 +734,9 @@ static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
|
||||
{
|
||||
struct dcerpc_binding_handle *h;
|
||||
struct rpcint_bh_state *hs;
|
||||
struct dcerpc_ncacn_conn *ncacn_conn = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
if (ndr_table) {
|
||||
abstract_syntax = &ndr_table->syntax_id;
|
||||
}
|
||||
|
||||
h = dcerpc_binding_handle_create(mem_ctx,
|
||||
&rpcint_bh_ops,
|
||||
NULL,
|
||||
@ -579,15 +748,22 @@ static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
hs->ndr_table = ndr_table;
|
||||
|
||||
status = make_internal_rpc_pipe_p(hs,
|
||||
abstract_syntax,
|
||||
status = make_internal_ncacn_conn(hs,
|
||||
ndr_table,
|
||||
remote_address,
|
||||
local_address,
|
||||
session_info,
|
||||
msg_ctx,
|
||||
&hs->p);
|
||||
&ncacn_conn);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
TALLOC_FREE(h);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = make_internal_dcesrv_connection(ncacn_conn,
|
||||
ndr_table,
|
||||
ncacn_conn,
|
||||
&hs->conn);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
TALLOC_FREE(h);
|
||||
return status;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,6 +32,9 @@
|
||||
#include "ntdomain.h"
|
||||
#include "librpc/rpc/dcesrv_core.h"
|
||||
#include "librpc/gen_ndr/ndr_winbind.h"
|
||||
#include "rpc_server/rpc_config.h"
|
||||
#include "rpc_server/rpc_server.h"
|
||||
#include "rpc_dce.h"
|
||||
|
||||
struct wbint_bh_state {
|
||||
struct winbindd_domain *domain;
|
||||
@ -320,6 +323,134 @@ static const struct dcerpc_binding_handle_ops wbint_bh_ops = {
|
||||
.do_ndr_print = wbint_bh_do_ndr_print,
|
||||
};
|
||||
|
||||
static NTSTATUS make_internal_ncacn_conn(TALLOC_CTX *mem_ctx,
|
||||
const struct ndr_interface_table *table,
|
||||
struct dcerpc_ncacn_conn **_out)
|
||||
{
|
||||
struct dcerpc_ncacn_conn *ncacn_conn = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
|
||||
if (ncacn_conn == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
ncacn_conn->p = talloc_zero(ncacn_conn, struct pipes_struct);
|
||||
if (ncacn_conn->p == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
ncacn_conn->p->mem_ctx = mem_ctx;
|
||||
|
||||
*_out = ncacn_conn;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
|
||||
fail:
|
||||
talloc_free(ncacn_conn);
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS find_ncalrpc_default_endpoint(struct dcesrv_context *dce_ctx,
|
||||
struct dcesrv_endpoint **ep)
|
||||
{
|
||||
TALLOC_CTX *tmp_ctx = NULL;
|
||||
struct dcerpc_binding *binding = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
tmp_ctx = talloc_new(dce_ctx);
|
||||
if (tmp_ctx == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some services use a rpcint binding handle in their initialization,
|
||||
* before the server is fully initialized. Search the NCALRPC endpoint
|
||||
* with and without endpoint
|
||||
*/
|
||||
status = dcerpc_parse_binding(tmp_ctx, "ncalrpc:", &binding);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = dcesrv_find_endpoint(dce_ctx, binding, ep);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = dcerpc_parse_binding(tmp_ctx, "ncalrpc:[DEFAULT]", &binding);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = dcesrv_find_endpoint(dce_ctx, binding, ep);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
talloc_free(tmp_ctx);
|
||||
return status;
|
||||
}
|
||||
|
||||
static NTSTATUS make_internal_dcesrv_connection(TALLOC_CTX *mem_ctx,
|
||||
const struct ndr_interface_table *ndr_table,
|
||||
struct dcerpc_ncacn_conn *ncacn_conn,
|
||||
struct dcesrv_connection **_out)
|
||||
{
|
||||
struct dcesrv_connection *conn = NULL;
|
||||
struct dcesrv_connection_context *context = NULL;
|
||||
struct dcesrv_endpoint *endpoint = NULL;
|
||||
NTSTATUS status;
|
||||
|
||||
conn = talloc_zero(mem_ctx, struct dcesrv_connection);
|
||||
if (conn == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
conn->dce_ctx = global_dcesrv_context();
|
||||
conn->preferred_transfer = &ndr_transfer_syntax_ndr;
|
||||
conn->transport.private_data = ncacn_conn;
|
||||
|
||||
status = find_ncalrpc_default_endpoint(conn->dce_ctx, &endpoint);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto fail;
|
||||
}
|
||||
conn->endpoint = endpoint;
|
||||
|
||||
conn->default_auth_state = talloc_zero(conn, struct dcesrv_auth);
|
||||
if (conn->default_auth_state == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
conn->default_auth_state->session_info = ncacn_conn->session_info;
|
||||
conn->default_auth_state->auth_finished = true;
|
||||
|
||||
context = talloc_zero(conn, struct dcesrv_connection_context);
|
||||
if (context == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
context->conn = conn;
|
||||
context->context_id = 0;
|
||||
context->transfer_syntax = *(conn->preferred_transfer);
|
||||
context->iface = find_interface_by_uuid(conn->endpoint,
|
||||
&ndr_table->syntax_id.uuid,
|
||||
ndr_table->syntax_id.if_version);
|
||||
if (context->iface == NULL) {
|
||||
status = NT_STATUS_RPC_INTERFACE_NOT_FOUND;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DLIST_ADD(conn->contexts, context);
|
||||
|
||||
*_out = conn;
|
||||
|
||||
return NT_STATUS_OK;
|
||||
fail:
|
||||
talloc_free(conn);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* initialise a wbint binding handle */
|
||||
struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
|
||||
struct winbindd_domain *domain,
|
||||
@ -344,70 +475,148 @@ struct dcerpc_binding_handle *wbint_binding_handle(TALLOC_CTX *mem_ctx,
|
||||
return h;
|
||||
}
|
||||
|
||||
static NTSTATUS rpcint_dispatch(struct dcesrv_call_state *call)
|
||||
{
|
||||
NTSTATUS status;
|
||||
struct ndr_pull *pull = NULL;
|
||||
struct ndr_push *push = NULL;
|
||||
struct data_blob_list_item *rep = NULL;
|
||||
|
||||
pull = ndr_pull_init_blob(&call->pkt.u.request.stub_and_verifier,
|
||||
call);
|
||||
if (pull == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
pull->flags |= LIBNDR_FLAG_REF_ALLOC;
|
||||
|
||||
call->ndr_pull = pull;
|
||||
|
||||
/* unravel the NDR for the packet */
|
||||
status = call->context->iface->ndr_pull(call, call, pull, &call->r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_ERR("DCE/RPC fault in call %s:%02X - %s\n",
|
||||
call->context->iface->name,
|
||||
call->pkt.u.request.opnum,
|
||||
dcerpc_errstr(call, call->fault_code));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = call->context->iface->local(call, call, call->r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_ERR("DCE/RPC fault in call %s:%02X - %s\n",
|
||||
call->context->iface->name,
|
||||
call->pkt.u.request.opnum,
|
||||
dcerpc_errstr(call, call->fault_code));
|
||||
return status;
|
||||
}
|
||||
|
||||
push = ndr_push_init_ctx(call);
|
||||
if (push == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
push->ptr_count = call->ndr_pull->ptr_count;
|
||||
|
||||
status = call->context->iface->ndr_push(call, call, push, call->r);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
DBG_ERR("DCE/RPC fault in call %s:%02X - %s\n",
|
||||
call->context->iface->name,
|
||||
call->pkt.u.request.opnum,
|
||||
dcerpc_errstr(call, call->fault_code));
|
||||
return status;
|
||||
}
|
||||
|
||||
rep = talloc_zero(call, struct data_blob_list_item);
|
||||
if (rep == NULL) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
rep->blob = ndr_push_blob(push);
|
||||
DLIST_ADD_END(call->replies, rep);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain,
|
||||
struct winbindd_cli_state *state)
|
||||
{
|
||||
const struct dcesrv_endpoint_server *ep_server = NULL;
|
||||
struct dcesrv_interface iface;
|
||||
const struct ndr_syntax_id *abstract_syntax;
|
||||
bool ok;
|
||||
struct dcerpc_ncacn_conn *ncacn_conn = NULL;
|
||||
struct dcesrv_connection *dcesrv_conn = NULL;
|
||||
struct dcesrv_call_state *dcesrv_call = NULL;
|
||||
struct data_blob_list_item *rep = NULL;
|
||||
uint32_t opnum = state->request->data.ndrcmd;
|
||||
struct pipes_struct *p;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
DATA_BLOB in;
|
||||
DATA_BLOB out;
|
||||
NTSTATUS status;
|
||||
|
||||
DBG_DEBUG("Running command %s (domain '%s')\n",
|
||||
ndr_table_winbind.calls[opnum].name,
|
||||
domain ? domain->name : "(null)");
|
||||
|
||||
ep_server = dcesrv_ep_server_byname(ndr_table_winbind.name);
|
||||
if (ep_server == NULL) {
|
||||
DBG_ERR("Failed to get DCE/RPC endpoint server '%s'\n",
|
||||
ndr_table_winbind.name);
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
abstract_syntax = &ndr_table_winbind.syntax_id;
|
||||
ok = ep_server->interface_by_uuid(&iface, &abstract_syntax->uuid,
|
||||
abstract_syntax->if_version);
|
||||
if (!ok) {
|
||||
DBG_ERR("Failed to get DCE/RPC interface\n");
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_stackframe();
|
||||
if (mem_ctx == NULL) {
|
||||
DBG_ERR("No memory");
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
||||
p = talloc_zero(mem_ctx, struct pipes_struct);
|
||||
if (p == NULL) {
|
||||
DBG_ERR("No memory\n");
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
p->mem_ctx = mem_ctx;
|
||||
|
||||
in = data_blob_const(state->request->extra_data.data,
|
||||
state->request->extra_len);
|
||||
|
||||
status = iface.local(p, opnum, mem_ctx, &in, &out);
|
||||
status = make_internal_ncacn_conn(mem_ctx,
|
||||
&ndr_table_winbind,
|
||||
&ncacn_conn);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
TALLOC_FREE(mem_ctx);
|
||||
return WINBINDD_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
state->response->extra_data.data =
|
||||
talloc_steal(state->mem_ctx, out.data);
|
||||
state->response->length += out.length;
|
||||
|
||||
TALLOC_FREE(mem_ctx);
|
||||
|
||||
if (state->response->extra_data.data == NULL) {
|
||||
return WINBINDD_ERROR;
|
||||
status = make_internal_dcesrv_connection(ncacn_conn,
|
||||
&ndr_table_winbind,
|
||||
ncacn_conn,
|
||||
&dcesrv_conn);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
return WINBINDD_OK;
|
||||
dcesrv_call = talloc_zero(dcesrv_conn, struct dcesrv_call_state);
|
||||
if (dcesrv_call == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dcesrv_call->conn = dcesrv_conn;
|
||||
dcesrv_call->context = dcesrv_conn->contexts;
|
||||
dcesrv_call->auth_state = dcesrv_conn->default_auth_state;
|
||||
|
||||
ZERO_STRUCT(dcesrv_call->pkt);
|
||||
dcesrv_call->pkt.u.bind.assoc_group_id = 0;
|
||||
status = dcesrv_call->conn->dce_ctx->callbacks.assoc_group.find(
|
||||
dcesrv_call);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(dcesrv_call->pkt);
|
||||
dcesrv_call->pkt.u.request.opnum = opnum;
|
||||
dcesrv_call->pkt.u.request.context_id = 0;
|
||||
dcesrv_call->pkt.u.request.stub_and_verifier =
|
||||
data_blob_const(state->request->extra_data.data,
|
||||
state->request->extra_len);
|
||||
|
||||
status = rpcint_dispatch(dcesrv_call);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rep = dcesrv_call->replies;
|
||||
DLIST_REMOVE(dcesrv_call->replies, rep);
|
||||
|
||||
state->response->extra_data.data = talloc_steal(state->mem_ctx,
|
||||
rep->blob.data);
|
||||
state->response->length += rep->blob.length;
|
||||
|
||||
talloc_free(rep);
|
||||
|
||||
out:
|
||||
talloc_free(mem_ctx);
|
||||
if (NT_STATUS_IS_OK(status)) {
|
||||
return WINBINDD_OK;
|
||||
}
|
||||
return WINBINDD_ERROR;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user