/* Recv the SAMR details (SamrConnect and SamrOpenDomain handle) and
 * open an LDAP connection */
static void init_domain_recv_samr(struct composite_context *ctx)
{
	const char *ldap_url;
	struct init_domain_state *state =
		talloc_get_type(ctx->async.private_data,
				struct init_domain_state);

	state->ctx->status = wb_connect_samr_recv(
		ctx, state->domain,
		&state->domain->samr_pipe,
		&state->domain->samr_handle, 
		&state->domain->domain_handle);
	if (!composite_is_ok(state->ctx)) return;

	talloc_steal(state->domain->samr_pipe, state->domain->samr_binding);

	state->domain->ldap_conn =
		ldap4_new_connection(state->domain, state->ctx->event_ctx);
	composite_nomem(state->domain->ldap_conn, state->ctx);

	ldap_url = talloc_asprintf(state, "ldap://%s/",
				   state->domain->dc_address);
	composite_nomem(ldap_url, state->ctx);

	ctx = ldap_connect_send(state->domain->ldap_conn, ldap_url);
	composite_continue(state->ctx, ctx, init_domain_recv_ldapconn, state);
}
/* Having make a netlogon connection (possibly secured with schannel),
 * make an LSA connection to the same DC, on the same IPC$ share */
static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
{
	struct init_domain_state *state =
		talloc_get_type(ctx->async.private_data,
				struct init_domain_state);

	state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state, 
						   &state->domain->netlogon_pipe);
	
	if (!composite_is_ok(state->ctx)) {
		talloc_free(state->domain->netlogon_binding);
		return;
	}
	talloc_steal(state->domain->netlogon_pipe, state->domain->netlogon_binding);

	state->domain->lsa_binding = init_domain_binding(state, &dcerpc_table_lsarpc);

	/* For debugging, it can be a real pain if all the traffic is encrypted */
	if (lp_winbind_sealed_pipes()) {
		state->domain->lsa_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL );
	} else {
		state->domain->lsa_binding->flags |= (DCERPC_SIGN);
	}

	state->domain->lsa_pipe = NULL;

	/* this will make the secondary connection on the same IPC$ share, 
	   secured with SPNEGO or NTLMSSP */
	ctx = dcerpc_secondary_connection_send(state->domain->netlogon_pipe,
					       state->domain->lsa_binding);
	composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state);
}
Exemple #3
0
static bool retry_with_schannel(struct init_domain_state *state, 
				struct dcerpc_binding *binding,
				const struct ndr_interface_table *table,
				void (*continuation)(struct composite_context *))
{
	struct composite_context *ctx;
	state->ctx->status = NT_STATUS_OK;
	if (state->domain->netlogon_binding->flags & DCERPC_SCHANNEL 
	    && !(binding->flags & DCERPC_SCHANNEL)) {
		/* Opening a policy handle failed, perhaps it was
		 * because we don't get a 'wrong password' error on
		 * NTLMSSP binds */

		/* Try again with schannel */
		binding->flags |= DCERPC_SCHANNEL;

		/* Try again, likewise on the same IPC$ share, 
		   secured with SCHANNEL */
		ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe,
							    binding,
							    table, 
							    state->domain->libnet_ctx->cred,
							    state->domain->libnet_ctx->lp_ctx);
		composite_continue(state->ctx, ctx, continuation, state);		
		return true;
	} else {
		return false;
	}
}
static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s)
{
	struct composite_context *c = s->creq;
	struct composite_context *creq;
	char *binding_str;

	binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal,target_hostname=%s]",
				      s->source_dsa.address,
				      s->source_dsa.dns_name);
	if (composite_nomem(binding_str, c)) return;

	c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi.binding);
	talloc_free(binding_str);
	if (!composite_is_ok(c)) return;

	if (DEBUGLEVEL >= 10) {
		c->status = dcerpc_binding_set_flags(s->drsuapi.binding,
						     DCERPC_DEBUG_PRINT_BOTH,
						     0);
		if (!composite_is_ok(c)) return;
	}

	creq = dcerpc_pipe_connect_b_send(s, s->drsuapi.binding, &ndr_table_drsuapi,
					  s->libnet->cred, s->libnet->event_ctx,
					  s->libnet->lp_ctx);
	composite_continue(c, creq, unbecomeDC_drsuapi_connect_recv, s);
}
BOOL lsa_domain_opened(struct libnet_context *ctx, const char *domain_name,
		       struct composite_context **parent_ctx,
		       struct libnet_DomainOpen *domain_open,
		       void (*continue_fn)(struct composite_context*),
		       void (*monitor)(struct monitor_msg*))
{
	struct composite_context *domopen_req;
	
	if (parent_ctx == NULL || *parent_ctx == NULL) return False;

	if (domain_name == NULL) {
		/*
		 * Try to guess the domain name from credentials,
		 * if it's not been explicitly specified.
		 */

		if (policy_handle_empty(&ctx->lsa.handle)) {
			domain_open->in.type        = DOMAIN_LSA;
			domain_open->in.domain_name = cli_credentials_get_domain(ctx->cred);
			domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;

		} else {
			composite_error(*parent_ctx, NT_STATUS_INVALID_PARAMETER);
			/* this ensures the calling function exits and composite function error
			   gets noticed quickly */
			return True;
		}

	} else {
		/*
		 * The domain name has been specified, so check whether the same
		 * domain is already opened. If it is - just return NULL. Start
		 * opening a new domain otherwise.
		 */

		if (policy_handle_empty(&ctx->lsa.handle) ||
		    !strequal(domain_name, ctx->lsa.name)) {
			domain_open->in.type        = DOMAIN_LSA;
			domain_open->in.domain_name = domain_name;
			domain_open->in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;

		} else {
			/* domain has already been opened and it's the same domain
			   as requested */
			return True;
		}
	}

	/* send request to open the domain */
	domopen_req = libnet_DomainOpen_send(ctx, domain_open, monitor);
	/* see the comment above to find out why true is returned here */
	if (composite_nomem(domopen_req, *parent_ctx)) return True;
	
	composite_continue(*parent_ctx, domopen_req, continue_fn, *parent_ctx);
	return False;
}
static void init_domain_recv_queryinfo(struct tevent_req *subreq)
{
	struct init_domain_state *state =
		tevent_req_callback_data(subreq,
		struct init_domain_state);
	struct lsa_DomainInfo *dominfo;
	struct composite_context *ctx;
	uint32_t lflags;

	state->ctx->status = dcerpc_lsa_QueryInfoPolicy_r_recv(subreq, state);
	TALLOC_FREE(subreq);
	if (!composite_is_ok(state->ctx)) return;
	state->ctx->status = state->queryinfo.out.result;
	if (!composite_is_ok(state->ctx)) return;

	if (!dom_sid_equal(state->domain->info->sid, &global_sid_Builtin)) {
		dominfo = &(*state->queryinfo.out.info)->account_domain;
		
		if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) {
			DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
				  state->domain->info->name,
				  dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe),
				  dominfo->name.string));
			composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
			return;
		}
		
		if (!dom_sid_equal(state->domain->info->sid, dominfo->sid)) {
			DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
				  dom_sid_string(state, state->domain->info->sid),
				  dcerpc_server_name(state->domain->libnet_ctx->lsa.pipe),
				  dom_sid_string(state, dominfo->sid)));
			composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
			return;
		}
	}

	state->domain->samr_binding = init_domain_binding(state, &ndr_table_samr);

	/* We want to use the same flags as the LSA pipe did (so, if
	 * it needed schannel, then we need that here too) */
	lflags = dcerpc_binding_get_flags(state->domain->lsa_binding);
	state->ctx->status = dcerpc_binding_set_flags(state->domain->samr_binding,
						      lflags, 0);
	if (!composite_is_ok(state->ctx)) return;

	state->domain->libnet_ctx->samr.pipe = NULL;
	state->domain->libnet_ctx->samr.samr_handle = NULL;

	ctx = wb_connect_samr_send(state, state->domain);
	composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
}
static BOOL torture_wbem_login_async(struct torture_context *torture)
{
    BOOL ret = True;
    TALLOC_CTX *mem_ctx = talloc_init("torture_wbem_login_async");
    struct com_context *com_ctx = NULL;
    const char *binding = NULL;
    struct composite_context *c = NULL;
    struct composite_context *new_ctx = NULL;
    struct GUID clsid;
    struct GUID iid;

    /*
     * Initialize our COM and DCOM contexts.
     */
    com_init_ctx(&com_ctx, NULL);
    dcom_client_init(com_ctx, cmdline_credentials);

    /*
     * Pull our needed test arguments from the torture parameters subsystem.
     */
    binding = torture_setting_string(torture, "binding", NULL);

    /*
     * Create a new composite for our call sequence, with the private data being
     * our return flag.
     */
    c = composite_create(mem_ctx, com_ctx->event_ctx);
    c->private_data = &ret;

    /*
     * Create the parameters needed for the activation call: we need the CLSID
     * and IID for the specific interface we're after.
     */
    GUID_from_string(CLSID_WBEMLEVEL1LOGIN, &clsid);
    GUID_from_string(COM_IWBEMLEVEL1LOGIN_UUID, &iid);

    /*
     * Fire off the asynchronous activation request with all the needed
     * input parameters. Then wait for the composite to be done within the
     * context of this function, which allows all the asynchronous magic to
     * still happen.
     */
    new_ctx = dcom_activate_send(c, &clsid, binding, 1, &iid, com_ctx);
    composite_continue(c, new_ctx, torture_wbem_login_async_cont, c);
    composite_wait(new_ctx);
    talloc_free(c);
    talloc_report_full(mem_ctx, stdout);

    return ret;
}
/* Having make a netlogon connection (possibly secured with schannel),
 * make an LSA connection to the same DC, on the same IPC$ share */
static void init_domain_recv_netlogonpipe(struct composite_context *ctx)
{
	struct init_domain_state *state =
		talloc_get_type(ctx->async.private_data,
				struct init_domain_state);
	uint32_t flags;

	state->ctx->status = dcerpc_pipe_connect_b_recv(ctx, state->domain, 
						   &state->domain->netlogon_pipe);
	
	if (!composite_is_ok(state->ctx)) {
		return;
	}
	talloc_reparent(state, state->domain->netlogon_pipe, state->domain->netlogon_binding);

	/* the netlogon connection is ready */
	tevent_queue_start(state->domain->netlogon_queue);

	state->domain->lsa_binding = init_domain_binding(state, &ndr_table_lsarpc);

	/* For debugging, it can be a real pain if all the traffic is encrypted */
	if (lpcfg_winbind_sealed_pipes(state->service->task->lp_ctx)) {
		flags = DCERPC_SIGN | DCERPC_SEAL;
	} else {
		flags = DCERPC_SIGN;
	}
	state->ctx->status = dcerpc_binding_set_flags(state->domain->lsa_binding,
						      flags, 0);
	if (!composite_is_ok(state->ctx)) {
		return;
	}

	state->domain->libnet_ctx->lsa.pipe = NULL;
	state->domain->libnet_ctx->lsa.lsa_handle = NULL;

	/* this will make the secondary connection on the same IPC$ share, 
	   secured with SPNEGO or NTLMSSP */
	ctx = dcerpc_secondary_auth_connection_send(state->domain->netlogon_pipe,
						    state->domain->lsa_binding,
						    &ndr_table_lsarpc,
						    state->domain->libnet_ctx->cred,
						    state->domain->libnet_ctx->lp_ctx
		);
	composite_continue(state->ctx, ctx, init_domain_recv_lsa_pipe, state);
}
Exemple #9
0
static void unbecomeDC_drsuapi_connect_send(struct libnet_UnbecomeDC_state *s)
{
	struct composite_context *c = s->creq;
	struct composite_context *creq;
	char *binding_str;

	binding_str = talloc_asprintf(s, "ncacn_ip_tcp:%s[seal]", s->source_dsa.dns_name);
	if (composite_nomem(binding_str, c)) return;

	c->status = dcerpc_parse_binding(s, binding_str, &s->drsuapi.binding);
	talloc_free(binding_str);
	if (!composite_is_ok(c)) return;

	creq = dcerpc_pipe_connect_b_send(s, s->drsuapi.binding, &ndr_table_drsuapi,
					  s->libnet->cred, s->libnet->event_ctx,
					  s->libnet->lp_ctx);
	composite_continue(c, creq, unbecomeDC_drsuapi_connect_recv, s);
}
static void init_domain_recv_queryinfo(struct rpc_request *req)
{
	struct init_domain_state *state =
		talloc_get_type(req->async.private_data, struct init_domain_state);
	struct lsa_DomainInfo *dominfo;
	struct composite_context *ctx;

	state->ctx->status = dcerpc_ndr_request_recv(req);
	if (!composite_is_ok(state->ctx)) return;
	state->ctx->status = state->queryinfo.out.result;
	if (!composite_is_ok(state->ctx)) return;

	dominfo = &state->queryinfo.out.info->account_domain;

	if (strcasecmp(state->domain->info->name, dominfo->name.string) != 0) {
		DEBUG(2, ("Expected domain name %s, DC %s said %s\n",
			  state->domain->info->name,
			  dcerpc_server_name(state->domain->lsa_pipe),
			  dominfo->name.string));
		composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
		return;
	}

	if (!dom_sid_equal(state->domain->info->sid, dominfo->sid)) {
		DEBUG(2, ("Expected domain sid %s, DC %s said %s\n",
			  dom_sid_string(state, state->domain->info->sid),
			  dcerpc_server_name(state->domain->lsa_pipe),
			  dom_sid_string(state, dominfo->sid)));
		composite_error(state->ctx, NT_STATUS_INVALID_DOMAIN_STATE);
		return;
	}

	state->domain->samr_binding = init_domain_binding(state, &dcerpc_table_samr);

	/* We want to use the same flags as the LSA pipe did (so, if
	 * it needed schannel, then we need that here too) */
	state->domain->samr_binding->flags = state->domain->lsa_binding->flags;

	state->domain->samr_pipe = NULL;

	ctx = wb_connect_samr_send(state, state->domain);
	composite_continue(state->ctx, ctx, init_domain_recv_samr, state);
}
struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
					      struct wbsrv_service *service,
					      struct wb_dom_info *dom_info)
{
	struct composite_context *result, *ctx;
	struct init_domain_state *state;

	result = composite_create(mem_ctx, service->task->event_ctx);
	if (result == NULL) goto failed;

	state = talloc_zero(result, struct init_domain_state);
	if (state == NULL) goto failed;
	state->ctx = result;
	result->private_data = state;

	state->service = service;

	state->domain = talloc(state, struct wbsrv_domain);
	if (state->domain == NULL) goto failed;

	state->domain->info = talloc_reference(state->domain, dom_info);
	if (state->domain->info == NULL) goto failed;

	/* Caller should check, but to be safe: */
	if (dom_info->num_dcs < 1) {
		goto failed;
	}
	
	/* For now, we just pick the first.  The next step will be to
	 * walk the entire list.  Also need to fix finddcs() to return
	 * the entire list */
	state->domain->dc_name = dom_info->dcs[0].name;
	state->domain->dc_address = dom_info->dcs[0].address;

	/* Create a credentials structure */
	state->domain->schannel_creds = cli_credentials_init(state->domain);
	if (state->domain->schannel_creds == NULL) goto failed;

	cli_credentials_set_event_context(state->domain->schannel_creds, service->task->event_ctx);

	cli_credentials_set_conf(state->domain->schannel_creds);

	/* Connect the machine account to the credentials */
	state->ctx->status =
		cli_credentials_set_machine_account(state->domain->
						    schannel_creds);
	if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;

	state->domain->netlogon_binding = init_domain_binding(state, &dcerpc_table_netlogon);

	state->domain->netlogon_pipe = NULL;

	if ((!cli_credentials_is_anonymous(state->domain->schannel_creds)) &&
	    ((lp_server_role() == ROLE_DOMAIN_MEMBER) &&
	     (dom_sid_equal(state->domain->info->sid,
			    state->service->primary_sid)))) {
		state->domain->netlogon_binding->flags |= DCERPC_SCHANNEL;

		/* For debugging, it can be a real pain if all the traffic is encrypted */
		if (lp_winbind_sealed_pipes()) {
			state->domain->netlogon_binding->flags |= (DCERPC_SIGN | DCERPC_SEAL );
		} else {
			state->domain->netlogon_binding->flags |= (DCERPC_SIGN);
		}
	}

	/* No encryption on anonymous pipes */

	ctx = dcerpc_pipe_connect_b_send(state, state->domain->netlogon_binding, 
					 &dcerpc_table_netlogon,
					 state->domain->schannel_creds,
					 service->task->event_ctx);
	
	if (composite_nomem(ctx, state->ctx)) {
		goto failed;
	}
	
	composite_continue(state->ctx, ctx, init_domain_recv_netlogonpipe,
			   state);
	return result;
 failed:
	talloc_free(result);
	return NULL;
}
struct composite_context *wb_init_domain_send(TALLOC_CTX *mem_ctx,
					      struct wbsrv_service *service,
					      struct wb_dom_info *dom_info)
{
	struct composite_context *result, *ctx;
	struct init_domain_state *state;

	result = composite_create(mem_ctx, service->task->event_ctx);
	if (result == NULL) goto failed;

	state = talloc_zero(result, struct init_domain_state);
	if (state == NULL) goto failed;
	state->ctx = result;
	result->private_data = state;

	state->service = service;

	state->domain = talloc(state, struct wbsrv_domain);
	if (state->domain == NULL) goto failed;

	state->domain->service = service;

	state->domain->info = talloc_reference(state->domain, dom_info);
	if (state->domain->info == NULL) goto failed;

	state->domain->dc_name = dom_info->dc->name;
	state->domain->dc_address = dom_info->dc->address;

	state->domain->libnet_ctx = libnet_context_init(service->task->event_ctx, 
							service->task->lp_ctx);
	if (state->domain->libnet_ctx == NULL) goto failed;
	talloc_steal(state->domain, state->domain->libnet_ctx);

	/* Create a credentials structure */
	state->domain->libnet_ctx->cred = cli_credentials_init(state->domain);
	if (state->domain->libnet_ctx->cred == NULL) goto failed;

	cli_credentials_set_conf(state->domain->libnet_ctx->cred, service->task->lp_ctx);

	/* Connect the machine account to the credentials */
	state->ctx->status =
		cli_credentials_set_machine_account(state->domain->libnet_ctx->cred, state->domain->libnet_ctx->lp_ctx);
	if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;

	state->domain->netlogon_binding = init_domain_binding(state, &ndr_table_netlogon);

	state->domain->netlogon_pipe = NULL;

	state->domain->netlogon_queue = tevent_queue_create(state->domain,
							    "netlogon_queue");
	if (state->domain->netlogon_queue == NULL) goto failed;

	/* We start the queue when the connection is usable */
	tevent_queue_stop(state->domain->netlogon_queue);

	if ((!cli_credentials_is_anonymous(state->domain->libnet_ctx->cred)) &&
	    ((lpcfg_server_role(service->task->lp_ctx) == ROLE_DOMAIN_MEMBER) ||
	     (lpcfg_server_role(service->task->lp_ctx) == ROLE_ACTIVE_DIRECTORY_DC)) &&
	    (dom_sid_equal(state->domain->info->sid,
			   state->service->primary_sid))) {
		uint32_t flags = DCERPC_SCHANNEL | DCERPC_SCHANNEL_AUTO;

		/* For debugging, it can be a real pain if all the traffic is encrypted */
		if (lpcfg_winbind_sealed_pipes(service->task->lp_ctx)) {
			flags |= DCERPC_SIGN | DCERPC_SEAL;
		} else {
			flags |= DCERPC_SIGN;
		}
		state->ctx->status = dcerpc_binding_set_flags(state->domain->netlogon_binding,
							      flags, 0);
		if (!NT_STATUS_IS_OK(state->ctx->status)) goto failed;
	}

	/* No encryption on anonymous pipes */

	ctx = dcerpc_pipe_connect_b_send(state, state->domain->netlogon_binding, 
					 &ndr_table_netlogon,
					 state->domain->libnet_ctx->cred,
					 service->task->event_ctx,
					 service->task->lp_ctx);
	
	if (composite_nomem(ctx, state->ctx)) {
		goto failed;
	}
	
	composite_continue(state->ctx, ctx, init_domain_recv_netlogonpipe,
			   state);
	return result;
 failed:
	talloc_free(result);
	return NULL;
}