libnet_rpc.c

来自「samba最新软件」· C语言 代码 · 共 975 行 · 第 1/2 页

C
975
字号
/*    Unix SMB/CIFS implementation.      Copyright (C) Stefan Metzmacher  2004   Copyright (C) Rafal Szczesniak   2005      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 "libnet/libnet.h"#include "libcli/libcli.h"#include "libcli/composite/composite.h"#include "librpc/rpc/dcerpc.h"#include "librpc/rpc/dcerpc_proto.h"#include "librpc/gen_ndr/ndr_lsa_c.h"#include "librpc/gen_ndr/ndr_samr.h"struct rpc_connect_srv_state {	struct libnet_context *ctx;	struct libnet_RpcConnect r;	const char *binding;	/* information about the progress */	void (*monitor_fn)(struct monitor_msg*);};static void continue_pipe_connect(struct composite_context *ctx);/** * Initiates connection to rpc pipe on remote server *  * @param ctx initialised libnet context * @param mem_ctx memory context of this call * @param r data structure containing necessary parameters and return values * @return composite context of this call **/static struct composite_context* libnet_RpcConnectSrv_send(struct libnet_context *ctx,							   TALLOC_CTX *mem_ctx,							   struct libnet_RpcConnect *r,							   void (*monitor)(struct monitor_msg*)){	struct composite_context *c;		struct rpc_connect_srv_state *s;	struct dcerpc_binding *b;	struct composite_context *pipe_connect_req;	/* composite context allocation and setup */	c = composite_create(ctx, ctx->event_ctx);	if (c == NULL) return c;	s = talloc_zero(c, struct rpc_connect_srv_state);	if (composite_nomem(s, c)) return c;	c->private_data = s;	s->monitor_fn   = monitor;	s->ctx = ctx;	s->r = *r;	ZERO_STRUCT(s->r.out);	/* prepare binding string */	switch (r->level) {	case LIBNET_RPC_CONNECT_SERVER:		s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.name);		break;	case LIBNET_RPC_CONNECT_SERVER_ADDRESS:		s->binding = talloc_asprintf(s, "ncacn_np:%s", r->in.address);		break;	case LIBNET_RPC_CONNECT_BINDING:		s->binding = talloc_strdup(s, r->in.binding);		break;	case LIBNET_RPC_CONNECT_DC:	case LIBNET_RPC_CONNECT_PDC:		/* this should never happen - DC and PDC level has a separate		   composite function */	case LIBNET_RPC_CONNECT_DC_INFO:		/* this should never happen - DC_INFO level has a separate		   composite function */		composite_error(c, NT_STATUS_INVALID_LEVEL);		return c;	}	/* parse binding string to the structure */	c->status = dcerpc_parse_binding(c, s->binding, &b);	if (!NT_STATUS_IS_OK(c->status)) {		DEBUG(0, ("Failed to parse dcerpc binding '%s'\n", s->binding));		composite_error(c, c->status);		return c;	}	if (r->level == LIBNET_RPC_CONNECT_SERVER_ADDRESS) {		b->target_hostname = talloc_reference(b, r->in.name);		if (composite_nomem(b->target_hostname, c)) {			return c;		}	}	/* connect to remote dcerpc pipe */	pipe_connect_req = dcerpc_pipe_connect_b_send(c, b, r->in.dcerpc_iface,						      ctx->cred, c->event_ctx,						      ctx->lp_ctx);	if (composite_nomem(pipe_connect_req, c)) return c;	composite_continue(c, pipe_connect_req, continue_pipe_connect, c);	return c;}/*  Step 2 of RpcConnectSrv - get rpc connection*/static void continue_pipe_connect(struct composite_context *ctx){	struct composite_context *c;	struct rpc_connect_srv_state *s;	c = talloc_get_type(ctx->async.private_data, struct composite_context);	s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);	/* receive result of rpc pipe connection */	c->status = dcerpc_pipe_connect_b_recv(ctx, c, &s->r.out.dcerpc_pipe);		/* post monitor message */	if (s->monitor_fn) {		struct monitor_msg msg;		struct msg_net_rpc_connect data;		struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;				/* prepare monitor message and post it */		data.host        = binding->host;		data.endpoint    = binding->endpoint;		data.transport   = binding->transport;		data.domain_name = binding->target_hostname;				msg.type      = mon_NetRpcConnect;		msg.data      = (void*)&data;		msg.data_size = sizeof(data);		s->monitor_fn(&msg);	}	composite_done(c);	}/** * Receives result of connection to rpc pipe on remote server * * @param c composite context * @param ctx initialised libnet context * @param mem_ctx memory context of this call * @param r data structure containing necessary parameters and return values * @return nt status of rpc connection **/static NTSTATUS libnet_RpcConnectSrv_recv(struct composite_context *c,					  struct libnet_context *ctx,					  TALLOC_CTX *mem_ctx,					  struct libnet_RpcConnect *r){	NTSTATUS status;	struct rpc_connect_srv_state *s = talloc_get_type(c->private_data,					  struct rpc_connect_srv_state);	status = composite_wait(c);	if (NT_STATUS_IS_OK(status)) {		/* move the returned rpc pipe between memory contexts */		s = talloc_get_type(c->private_data, struct rpc_connect_srv_state);		r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);		/* reference created pipe structure to long-term libnet_context		   so that it can be used by other api functions even after short-term		   mem_ctx is freed */		if (r->in.dcerpc_iface == &ndr_table_samr) {			ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);		} else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {			ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);		}		r->out.error_string = talloc_strdup(mem_ctx, "Success");	} else {		r->out.error_string = talloc_asprintf(mem_ctx, "Error: %s", nt_errstr(status));	}	talloc_free(c);	return status;}struct rpc_connect_dc_state {	struct libnet_context *ctx;	struct libnet_RpcConnect r;	struct libnet_RpcConnect r2;	struct libnet_LookupDCs f;	const char *connect_name;	/* information about the progress */	void (*monitor_fn)(struct monitor_msg *);};static void continue_lookup_dc(struct composite_context *ctx);static void continue_rpc_connect(struct composite_context *ctx);/** * Initiates connection to rpc pipe on domain pdc *  * @param ctx initialised libnet context * @param mem_ctx memory context of this call * @param r data structure containing necessary parameters and return values * @return composite context of this call **/static struct composite_context* libnet_RpcConnectDC_send(struct libnet_context *ctx,							  TALLOC_CTX *mem_ctx,							  struct libnet_RpcConnect *r,							  void (*monitor)(struct monitor_msg *msg)){	struct composite_context *c;	struct rpc_connect_dc_state *s;	struct composite_context *lookup_dc_req;	/* composite context allocation and setup */	c = composite_create(ctx, ctx->event_ctx);	if (c == NULL) return c;	s = talloc_zero(c, struct rpc_connect_dc_state);	if (composite_nomem(s, c)) return c;	c->private_data = s;	s->monitor_fn   = monitor;	s->ctx = ctx;	s->r   = *r;	ZERO_STRUCT(s->r.out);	switch (r->level) {	case LIBNET_RPC_CONNECT_PDC:		s->f.in.name_type = NBT_NAME_PDC;		break;	case LIBNET_RPC_CONNECT_DC:		s->f.in.name_type = NBT_NAME_LOGON;		break;	default:		break;	}	s->f.in.domain_name = r->in.name;	s->f.out.num_dcs    = 0;	s->f.out.dcs        = NULL;	/* find the domain pdc first */	lookup_dc_req = libnet_LookupDCs_send(ctx, c, &s->f);	if (composite_nomem(lookup_dc_req, c)) return c;	composite_continue(c, lookup_dc_req, continue_lookup_dc, c);	return c;}/*  Step 2 of RpcConnectDC: get domain controller name and  initiate RpcConnect to it*/static void continue_lookup_dc(struct composite_context *ctx){	struct composite_context *c;	struct rpc_connect_dc_state *s;	struct composite_context *rpc_connect_req;	struct monitor_msg msg;	struct msg_net_lookup_dc data;		c = talloc_get_type(ctx->async.private_data, struct composite_context);	s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);		/* receive result of domain controller lookup */	c->status = libnet_LookupDCs_recv(ctx, c, &s->f);	if (!composite_is_ok(c)) return;	/* decide on preferred address type depending on DC type */	s->connect_name = s->f.out.dcs[0].name;	/* post monitor message */	if (s->monitor_fn) {		/* prepare a monitor message and post it */		data.domain_name = s->f.in.domain_name;		data.hostname    = s->f.out.dcs[0].name;		data.address     = s->f.out.dcs[0].address;				msg.type         = mon_NetLookupDc;		msg.data         = &data;		msg.data_size    = sizeof(data);		s->monitor_fn(&msg);	}	/* ok, pdc has been found so do attempt to rpc connect */	s->r2.level	       = LIBNET_RPC_CONNECT_SERVER_ADDRESS;	/* this will cause yet another name resolution, but at least	 * we pass the right name down the stack now */	s->r2.in.name          = talloc_strdup(s, s->connect_name);	s->r2.in.address       = talloc_steal(s, s->f.out.dcs[0].address);	s->r2.in.dcerpc_iface  = s->r.in.dcerpc_iface;		/* send rpc connect request to the server */	rpc_connect_req = libnet_RpcConnectSrv_send(s->ctx, c, &s->r2, s->monitor_fn);	if (composite_nomem(rpc_connect_req, c)) return;	composite_continue(c, rpc_connect_req, continue_rpc_connect, c);}/*  Step 3 of RpcConnectDC: get rpc connection to the server*/static void continue_rpc_connect(struct composite_context *ctx){	struct composite_context *c;	struct rpc_connect_dc_state *s;	c = talloc_get_type(ctx->async.private_data, struct composite_context);	s = talloc_get_type(c->private_data, struct rpc_connect_dc_state);	c->status = libnet_RpcConnectSrv_recv(ctx, s->ctx, c, &s->r2);	/* error string is to be passed anyway */	s->r.out.error_string  = s->r2.out.error_string;	if (!composite_is_ok(c)) return;	s->r.out.dcerpc_pipe = s->r2.out.dcerpc_pipe;		/* post monitor message */	if (s->monitor_fn) {		struct monitor_msg msg;		struct msg_net_rpc_connect data;		struct dcerpc_binding *binding = s->r.out.dcerpc_pipe->binding;		data.host        = binding->host;		data.endpoint    = binding->endpoint;		data.transport   = binding->transport;		data.domain_name = binding->target_hostname;				msg.type      = mon_NetRpcConnect;		msg.data      = (void*)&data;		msg.data_size = sizeof(data);		s->monitor_fn(&msg);	}	composite_done(c);}/** * Receives result of connection to rpc pipe on domain pdc * * @param c composite context * @param ctx initialised libnet context * @param mem_ctx memory context of this call * @param r data structure containing necessary parameters and return values * @return nt status of rpc connection **/static NTSTATUS libnet_RpcConnectDC_recv(struct composite_context *c,					 struct libnet_context *ctx,					 TALLOC_CTX *mem_ctx,					 struct libnet_RpcConnect *r){	NTSTATUS status;	struct rpc_connect_dc_state *s = talloc_get_type(c->private_data,					 struct rpc_connect_dc_state);	status = composite_wait(c);	if (NT_STATUS_IS_OK(status)) {		/* move connected rpc pipe between memory contexts */		r->out.dcerpc_pipe = talloc_steal(mem_ctx, s->r.out.dcerpc_pipe);		/* reference created pipe structure to long-term libnet_context		   so that it can be used by other api functions even after short-term		   mem_ctx is freed */		if (r->in.dcerpc_iface == &ndr_table_samr) {			ctx->samr.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);		} else if (r->in.dcerpc_iface == &ndr_table_lsarpc) {			ctx->lsa.pipe = talloc_reference(ctx, r->out.dcerpc_pipe);		}	} else {		r->out.error_string = talloc_asprintf(mem_ctx,						      "Failed to rpc connect: %s",						      nt_errstr(status));	}	talloc_free(c);	return status;}struct rpc_connect_dci_state {	struct libnet_context *ctx;	struct libnet_RpcConnect r;	struct libnet_RpcConnect rpc_conn;	struct policy_handle lsa_handle;	struct lsa_QosInfo qos;	struct lsa_ObjectAttribute attr;	struct lsa_OpenPolicy2 lsa_open_policy;	struct dcerpc_pipe *lsa_pipe;	struct lsa_QueryInfoPolicy2 lsa_query_info2;	struct lsa_QueryInfoPolicy lsa_query_info;	struct dcerpc_binding *final_binding;	struct dcerpc_pipe *final_pipe;	/* information about the progress */	void (*monitor_fn)(struct monitor_msg*);};static void continue_dci_rpc_connect(struct composite_context *ctx);static void continue_lsa_policy(struct rpc_request *req);static void continue_lsa_query_info(struct rpc_request *req);static void continue_lsa_query_info2(struct rpc_request *req);static void continue_epm_map_binding(struct composite_context *ctx);static void continue_secondary_conn(struct composite_context *ctx);static void continue_epm_map_binding_send(struct composite_context *c);/** * Initiates connection to rpc pipe on remote server or pdc. Received result * contains info on the domain name, domain sid and realm. *  * @param ctx initialised libnet context * @param mem_ctx memory context of this call * @param r data structure containing necessary parameters and return values. Must be a talloc context * @return composite context of this call **/static struct composite_context* libnet_RpcConnectDCInfo_send(struct libnet_context *ctx,							      TALLOC_CTX *mem_ctx,							      struct libnet_RpcConnect *r,							      void (*monitor)(struct monitor_msg*)){	struct composite_context *c, *conn_req;	struct rpc_connect_dci_state *s;	/* composite context allocation and setup */	c = composite_create(ctx, ctx->event_ctx);	if (c == NULL) return c;	s = talloc_zero(c, struct rpc_connect_dci_state);	if (composite_nomem(s, c)) return c;	c->private_data = s;	s->monitor_fn   = monitor;	s->ctx = ctx;	s->r   = *r;	ZERO_STRUCT(s->r.out);	/* proceed to pure rpc connection if the binding string is provided,	   otherwise try to connect domain controller */	if (r->in.binding == NULL) {		s->rpc_conn.in.name    = r->in.name;		s->rpc_conn.level      = LIBNET_RPC_CONNECT_DC;	} else {		s->rpc_conn.in.binding = r->in.binding;		s->rpc_conn.level      = LIBNET_RPC_CONNECT_BINDING;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?