mirror of
				https://github.com/samba-team/samba.git
				synced 2025-10-31 12:23:52 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			974 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			974 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 
 | |
|    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/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;
 | |
| 	}
 | |
| 
 | |
| 	/* we need to query information on lsarpc interface first */
 | |
| 	s->rpc_conn.in.dcerpc_iface    = &ndr_table_lsarpc;
 | |
| 	
 | |
| 	/* request connection to the lsa pipe on the pdc */
 | |
| 	conn_req = libnet_RpcConnect_send(ctx, c, &s->rpc_conn, s->monitor_fn);
 | |
| 	if (composite_nomem(c, conn_req)) return c;
 | |
| 
 | |
| 	composite_continue(c, conn_req, continue_dci_rpc_connect, c);
 | |
| 	return c;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Step 2 of RpcConnectDCInfo: receive opened rpc pipe and open
 | |
|   lsa policy handle
 | |
| */
 | |
| static void continue_dci_rpc_connect(struct composite_context *ctx)
 | |
| {
 | |
| 	struct composite_context *c;
 | |
| 	struct rpc_connect_dci_state *s;
 | |
| 	struct rpc_request *open_pol_req;
 | |
| 
 | |
| 	c = talloc_get_type(ctx->async.private_data, struct composite_context);
 | |
| 	s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 | |
| 
 | |
| 	c->status = libnet_RpcConnect_recv(ctx, s->ctx, c, &s->rpc_conn);
 | |
| 	if (!NT_STATUS_IS_OK(c->status)) {
 | |
| 		composite_error(c, c->status);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* 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);
 | |
| 	}
 | |
| 
 | |
| 	/* prepare to open a policy handle on lsa pipe */
 | |
| 	s->lsa_pipe = s->ctx->lsa.pipe;
 | |
| 	
 | |
| 	s->qos.len                 = 0;
 | |
| 	s->qos.impersonation_level = 2;
 | |
| 	s->qos.context_mode        = 1;
 | |
| 	s->qos.effective_only      = 0;
 | |
| 
 | |
| 	s->attr.sec_qos = &s->qos;
 | |
| 
 | |
| 	s->lsa_open_policy.in.attr        = &s->attr;
 | |
| 	s->lsa_open_policy.in.system_name = talloc_asprintf(c, "\\");
 | |
| 	if (composite_nomem(s->lsa_open_policy.in.system_name, c)) return;
 | |
| 
 | |
| 	s->lsa_open_policy.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
 | |
| 	s->lsa_open_policy.out.handle     = &s->lsa_handle;
 | |
| 
 | |
| 	open_pol_req = dcerpc_lsa_OpenPolicy2_send(s->lsa_pipe, c, &s->lsa_open_policy);
 | |
| 	if (composite_nomem(open_pol_req, c)) return;
 | |
| 
 | |
| 	composite_continue_rpc(c, open_pol_req, continue_lsa_policy, c);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Step 3 of RpcConnectDCInfo: Get policy handle and query lsa info
 | |
|   for kerberos realm (dns name) and guid. The query may fail.
 | |
| */
 | |
| static void continue_lsa_policy(struct rpc_request *req)
 | |
| {
 | |
| 	struct composite_context *c;
 | |
| 	struct rpc_connect_dci_state *s;
 | |
| 	struct rpc_request *query_info_req;
 | |
| 
 | |
| 	c = talloc_get_type(req->async.private_data, struct composite_context);
 | |
| 	s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 | |
| 
 | |
| 	c->status = dcerpc_ndr_request_recv(req);
 | |
| 	if (!NT_STATUS_IS_OK(c->status)) {
 | |
| 		composite_error(c, c->status);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (NT_STATUS_EQUAL(s->lsa_open_policy.out.result, NT_STATUS_RPC_PROTSEQ_NOT_SUPPORTED)) {
 | |
| 		s->r.out.realm = NULL;
 | |
| 		s->r.out.guid  = NULL;
 | |
| 		s->r.out.domain_name = NULL;
 | |
| 		s->r.out.domain_sid  = NULL;
 | |
| 
 | |
| 		/* Skip to the creating the actual connection, no info available on this transport */
 | |
| 		continue_epm_map_binding_send(c);
 | |
| 		return;
 | |
| 
 | |
| 	} else if (!NT_STATUS_IS_OK(s->lsa_open_policy.out.result)) {
 | |
| 		composite_error(c, s->lsa_open_policy.out.result);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* post monitor message */
 | |
| 	if (s->monitor_fn) {
 | |
| 		struct monitor_msg msg;
 | |
| 
 | |
| 		msg.type      = mon_LsaOpenPolicy;
 | |
| 		msg.data      = NULL;
 | |
| 		msg.data_size = 0;
 | |
| 		s->monitor_fn(&msg);
 | |
| 	}
 | |
| 
 | |
| 	/* query lsa info for dns domain name and guid */
 | |
| 	s->lsa_query_info2.in.handle = &s->lsa_handle;
 | |
| 	s->lsa_query_info2.in.level  = LSA_POLICY_INFO_DNS;
 | |
| 
 | |
| 	query_info_req = dcerpc_lsa_QueryInfoPolicy2_send(s->lsa_pipe, c, &s->lsa_query_info2);
 | |
| 	if (composite_nomem(query_info_req, c)) return;
 | |
| 
 | |
| 	composite_continue_rpc(c, query_info_req, continue_lsa_query_info2, c);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Step 4 of RpcConnectDCInfo: Get realm and guid if provided (rpc call
 | |
|   may result in failure) and query lsa info for domain name and sid.
 | |
| */
 | |
| static void continue_lsa_query_info2(struct rpc_request *req)
 | |
| {	
 | |
| 	struct composite_context *c;
 | |
| 	struct rpc_connect_dci_state *s;
 | |
| 	struct rpc_request *query_info_req;
 | |
| 
 | |
| 	c = talloc_get_type(req->async.private_data, struct composite_context);
 | |
| 	s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 | |
| 
 | |
| 	c->status = dcerpc_ndr_request_recv(req);
 | |
| 	
 | |
| 	/* In case of error just null the realm and guid and proceed
 | |
| 	   to the next step. After all, it doesn't have to be AD domain
 | |
| 	   controller we talking to - NT-style PDC also counts */
 | |
| 
 | |
| 	if (NT_STATUS_EQUAL(c->status, NT_STATUS_NET_WRITE_FAULT)) {
 | |
| 		s->r.out.realm = NULL;
 | |
| 		s->r.out.guid  = NULL;
 | |
| 
 | |
| 	} else {
 | |
| 		if (!NT_STATUS_IS_OK(c->status)) {
 | |
| 			s->r.out.error_string = talloc_asprintf(c,
 | |
| 								"lsa_QueryInfoPolicy2 failed: %s",
 | |
| 								nt_errstr(c->status));
 | |
| 			composite_error(c, c->status);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		if (!NT_STATUS_IS_OK(s->lsa_query_info2.out.result)) {
 | |
| 			s->r.out.error_string = talloc_asprintf(c,
 | |
| 								"lsa_QueryInfoPolicy2 failed: %s",
 | |
| 								nt_errstr(s->lsa_query_info2.out.result));
 | |
| 			composite_error(c, s->lsa_query_info2.out.result);
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		/* Copy the dns domain name and guid from the query result */
 | |
| 
 | |
| 		/* this should actually be a conversion from lsa_StringLarge */
 | |
| 		s->r.out.realm = s->lsa_query_info2.out.info->dns.dns_domain.string;
 | |
| 		s->r.out.guid  = talloc(c, struct GUID);
 | |
| 		if (composite_nomem(s->r.out.guid, c)) {
 | |
| 			s->r.out.error_string = NULL;
 | |
| 			return;
 | |
| 		}
 | |
| 		*s->r.out.guid = s->lsa_query_info2.out.info->dns.domain_guid;
 | |
| 	}
 | |
| 
 | |
| 	/* post monitor message */
 | |
| 	if (s->monitor_fn) {
 | |
| 		struct monitor_msg msg;
 | |
| 		
 | |
| 		msg.type      = mon_LsaQueryPolicy;
 | |
| 		msg.data      = NULL;
 | |
| 		msg.data_size = 0;
 | |
| 		s->monitor_fn(&msg);
 | |
| 	}
 | |
| 
 | |
| 	/* query lsa info for domain name and sid */
 | |
| 	s->lsa_query_info.in.handle = &s->lsa_handle;
 | |
| 	s->lsa_query_info.in.level  = LSA_POLICY_INFO_DOMAIN;
 | |
| 
 | |
| 	query_info_req = dcerpc_lsa_QueryInfoPolicy_send(s->lsa_pipe, c, &s->lsa_query_info);
 | |
| 	if (composite_nomem(query_info_req, c)) return;
 | |
| 
 | |
| 	composite_continue_rpc(c, query_info_req, continue_lsa_query_info, c);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Step 5 of RpcConnectDCInfo: Get domain name and sid
 | |
| */
 | |
| static void continue_lsa_query_info(struct rpc_request *req)
 | |
| {
 | |
| 	struct composite_context *c;
 | |
| 	struct rpc_connect_dci_state *s;
 | |
| 
 | |
| 	c = talloc_get_type(req->async.private_data, struct composite_context);
 | |
| 	s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 | |
| 
 | |
| 	c->status = dcerpc_ndr_request_recv(req);
 | |
| 	if (!NT_STATUS_IS_OK(c->status)) {
 | |
| 		s->r.out.error_string = talloc_asprintf(c,
 | |
| 							"lsa_QueryInfoPolicy failed: %s",
 | |
| 							nt_errstr(c->status));
 | |
| 		composite_error(c, c->status);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* post monitor message */
 | |
| 	if (s->monitor_fn) {
 | |
| 		struct monitor_msg msg;
 | |
| 		
 | |
| 		msg.type      = mon_LsaQueryPolicy;
 | |
| 		msg.data      = NULL;
 | |
| 		msg.data_size = 0;
 | |
| 		s->monitor_fn(&msg);
 | |
| 	}
 | |
| 
 | |
| 	/* Copy the domain name and sid from the query result */
 | |
| 	s->r.out.domain_sid  = s->lsa_query_info.out.info->domain.sid;
 | |
| 	s->r.out.domain_name = s->lsa_query_info.out.info->domain.name.string;
 | |
| 
 | |
| 	continue_epm_map_binding_send(c);
 | |
| }
 | |
| 
 | |
| /* 
 | |
|    Step 5 (continued) of RpcConnectDCInfo: request endpoint
 | |
|    map binding.
 | |
| 
 | |
|    We may short-cut to this step if we don't support LSA OpenPolicy on this transport
 | |
| */
 | |
| static void continue_epm_map_binding_send(struct composite_context *c)
 | |
| {
 | |
| 	struct rpc_connect_dci_state *s;
 | |
| 	struct composite_context *epm_map_req;
 | |
| 	s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 | |
| 
 | |
| 	/* prepare to get endpoint mapping for the requested interface */
 | |
| 	s->final_binding = talloc(s, struct dcerpc_binding);
 | |
| 	if (composite_nomem(s->final_binding, c)) return;
 | |
| 	
 | |
| 	*s->final_binding = *s->lsa_pipe->binding;
 | |
| 	/* Ensure we keep hold of the member elements */
 | |
| 	if (composite_nomem(talloc_reference(s->final_binding, s->lsa_pipe->binding), c)) return;
 | |
| 
 | |
| 	epm_map_req = dcerpc_epm_map_binding_send(c, s->final_binding, s->r.in.dcerpc_iface,
 | |
| 						  s->lsa_pipe->conn->event_ctx, s->ctx->lp_ctx);
 | |
| 	if (composite_nomem(epm_map_req, c)) return;
 | |
| 
 | |
| 	composite_continue(c, epm_map_req, continue_epm_map_binding, c);
 | |
| }
 | |
| 
 | |
| /*
 | |
|   Step 6 of RpcConnectDCInfo: Receive endpoint mapping and create secondary
 | |
|   rpc connection derived from already used pipe but connected to the requested
 | |
|   one (as specified in libnet_RpcConnect structure)
 | |
| */
 | |
| static void continue_epm_map_binding(struct composite_context *ctx)
 | |
| {
 | |
| 	struct composite_context *c, *sec_conn_req;
 | |
| 	struct rpc_connect_dci_state *s;
 | |
| 
 | |
| 	c = talloc_get_type(ctx->async.private_data, struct composite_context);
 | |
| 	s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 | |
| 
 | |
| 	c->status = dcerpc_epm_map_binding_recv(ctx);
 | |
| 	if (!NT_STATUS_IS_OK(c->status)) {
 | |
| 		s->r.out.error_string = talloc_asprintf(c,
 | |
| 							"failed to map pipe with endpoint mapper - %s",
 | |
| 							nt_errstr(c->status));
 | |
| 		composite_error(c, c->status);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* create secondary connection derived from lsa pipe */
 | |
| 	sec_conn_req = dcerpc_secondary_connection_send(s->lsa_pipe, s->final_binding);
 | |
| 	if (composite_nomem(sec_conn_req, c)) return;
 | |
| 
 | |
| 	composite_continue(c, sec_conn_req, continue_secondary_conn, c);
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|   Step 7 of RpcConnectDCInfo: Get actual pipe to be returned
 | |
|   and complete this composite call
 | |
| */
 | |
| static void continue_secondary_conn(struct composite_context *ctx)
 | |
| {
 | |
| 	struct composite_context *c;
 | |
| 	struct rpc_connect_dci_state *s;
 | |
| 
 | |
| 	c = talloc_get_type(ctx->async.private_data, struct composite_context);
 | |
| 	s = talloc_get_type(c->private_data, struct rpc_connect_dci_state);
 | |
| 
 | |
| 	c->status = dcerpc_secondary_connection_recv(ctx, &s->final_pipe);
 | |
| 	if (!NT_STATUS_IS_OK(c->status)) {
 | |
| 		s->r.out.error_string = talloc_asprintf(c,
 | |
| 							"secondary connection failed: %s",
 | |
| 							nt_errstr(c->status));
 | |
| 		
 | |
| 		composite_error(c, c->status);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	s->r.out.dcerpc_pipe = s->final_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 and gets basic
 | |
|  * domain info (name, sid, realm, guid)
 | |
|  *
 | |
|  * @param c composite context
 | |
|  * @param ctx initialised libnet context
 | |
|  * @param mem_ctx memory context of this call
 | |
|  * @param r data structure containing return values
 | |
|  * @return nt status of rpc connection
 | |
|  **/
 | |
| 
 | |
| static NTSTATUS libnet_RpcConnectDCInfo_recv(struct composite_context *c, struct libnet_context *ctx,
 | |
| 					     TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
 | |
| {
 | |
| 	NTSTATUS status;
 | |
| 	struct rpc_connect_dci_state *s = talloc_get_type(c->private_data,
 | |
| 					  struct rpc_connect_dci_state);
 | |
| 
 | |
| 	status = composite_wait(c);
 | |
| 	if (NT_STATUS_IS_OK(status)) {
 | |
| 		r->out.realm        = talloc_steal(mem_ctx, s->r.out.realm);
 | |
| 		r->out.guid         = talloc_steal(mem_ctx, s->r.out.guid);
 | |
| 		r->out.domain_name  = talloc_steal(mem_ctx, s->r.out.domain_name);
 | |
| 		r->out.domain_sid   = talloc_steal(mem_ctx, s->r.out.domain_sid);
 | |
| 
 | |
| 		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 {
 | |
| 		if (s->r.out.error_string) {
 | |
| 			r->out.error_string = talloc_steal(mem_ctx, s->r.out.error_string);
 | |
| 		} else if (r->in.binding == NULL) {
 | |
| 			r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC failed: %s", nt_errstr(status));
 | |
| 		} else {
 | |
| 			r->out.error_string = talloc_asprintf(mem_ctx, "Connection to DC %s failed: %s", 
 | |
| 							      r->in.binding, nt_errstr(status));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	talloc_free(c);
 | |
| 	return status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Initiates connection to rpc pipe on remote server or pdc, optionally
 | |
|  * providing domain info
 | |
|  * 
 | |
|  * @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
 | |
|  **/
 | |
| 
 | |
| struct composite_context* libnet_RpcConnect_send(struct libnet_context *ctx,
 | |
| 						 TALLOC_CTX *mem_ctx,
 | |
| 						 struct libnet_RpcConnect *r,
 | |
| 						 void (*monitor)(struct monitor_msg*))
 | |
| {
 | |
| 	struct composite_context *c;
 | |
| 
 | |
| 	switch (r->level) {
 | |
| 	case LIBNET_RPC_CONNECT_SERVER:
 | |
| 	case LIBNET_RPC_CONNECT_SERVER_ADDRESS:
 | |
| 	case LIBNET_RPC_CONNECT_BINDING:
 | |
| 		c = libnet_RpcConnectSrv_send(ctx, mem_ctx, r, monitor);
 | |
| 		break;
 | |
| 
 | |
| 	case LIBNET_RPC_CONNECT_PDC:
 | |
| 	case LIBNET_RPC_CONNECT_DC:
 | |
| 		c = libnet_RpcConnectDC_send(ctx, mem_ctx, r, monitor);
 | |
| 		break;
 | |
| 
 | |
| 	case LIBNET_RPC_CONNECT_DC_INFO:
 | |
| 		c = libnet_RpcConnectDCInfo_send(ctx, mem_ctx, r, monitor);
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		c = talloc_zero(mem_ctx, struct composite_context);
 | |
| 		composite_error(c, NT_STATUS_INVALID_LEVEL);
 | |
| 	}
 | |
| 
 | |
| 	return c;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Receives result of connection to rpc pipe on remote server or 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
 | |
|  **/
 | |
| 
 | |
| NTSTATUS libnet_RpcConnect_recv(struct composite_context *c, struct libnet_context *ctx,
 | |
| 				TALLOC_CTX *mem_ctx, struct libnet_RpcConnect *r)
 | |
| {
 | |
| 	switch (r->level) {
 | |
| 	case LIBNET_RPC_CONNECT_SERVER:
 | |
| 	case LIBNET_RPC_CONNECT_BINDING:
 | |
| 		return libnet_RpcConnectSrv_recv(c, ctx, mem_ctx, r);
 | |
| 
 | |
| 	case LIBNET_RPC_CONNECT_PDC:
 | |
| 	case LIBNET_RPC_CONNECT_DC:
 | |
| 		return libnet_RpcConnectDC_recv(c, ctx, mem_ctx, r);
 | |
| 
 | |
| 	case LIBNET_RPC_CONNECT_DC_INFO:
 | |
| 		return libnet_RpcConnectDCInfo_recv(c, ctx, mem_ctx, r);
 | |
| 
 | |
| 	default:
 | |
| 		ZERO_STRUCT(r->out);
 | |
| 		return NT_STATUS_INVALID_LEVEL;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Connect to a rpc pipe on a remote server - sync version
 | |
|  *
 | |
|  * @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
 | |
|  **/
 | |
| 
 | |
| NTSTATUS libnet_RpcConnect(struct libnet_context *ctx, TALLOC_CTX *mem_ctx,
 | |
| 			   struct libnet_RpcConnect *r)
 | |
| {
 | |
| 	struct composite_context *c;
 | |
| 	
 | |
| 	c = libnet_RpcConnect_send(ctx, mem_ctx, r, NULL);
 | |
| 	return libnet_RpcConnect_recv(c, ctx, mem_ctx, r);
 | |
| }
 |