Пример #1
0
/*
  Receive a bind reply from the transport
*/
static void dcerpc_bind_recv_handler(struct rpc_request *req, 
				     DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
{
	struct composite_context *c;
	struct dcerpc_connection *conn;

	c = talloc_get_type(req->async.private_data, struct composite_context);

	if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
		DEBUG(2,("dcerpc: bind_nak reason %d\n",
			 pkt->u.bind_nak.reject_reason));
		composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
						     reject_reason));
		return;
	}

	if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
	    (pkt->u.bind_ack.num_results == 0) ||
	    (pkt->u.bind_ack.ctx_list[0].result != 0)) {
		composite_error(c, NT_STATUS_NET_WRITE_FAULT);
		return;
	}

	conn = req->p->conn;

	conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
	conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;

	if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
	    (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
		conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
	}

	if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
	    (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
		conn->flags |= DCERPC_HEADER_SIGNING;
	}

	/* the bind_ack might contain a reply set of credentials */
	if (conn->security_state.auth_info &&
	    pkt->u.bind_ack.auth_info.length) {
		enum ndr_err_code ndr_err;
		ndr_err = ndr_pull_struct_blob(
			&pkt->u.bind_ack.auth_info, conn,
			NULL,
			conn->security_state.auth_info,
			(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			c->status = ndr_map_error2ntstatus(ndr_err);
			if (!composite_is_ok(c)) return;
		}
	}

	req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;

	composite_done(c);
}
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);
}
Пример #3
0
/*
  Send request to do a non-authenticated dcerpc bind
*/
struct composite_context *dcerpc_bind_auth_none_send(TALLOC_CTX *mem_ctx,
						     struct dcerpc_pipe *p,
						     const struct ndr_interface_table *table)
{
	struct ndr_syntax_id syntax;
	struct ndr_syntax_id transfer_syntax;

	struct composite_context *c;

	c = composite_create(mem_ctx, p->conn->event_ctx);
	if (c == NULL) return NULL;

	c->status = dcerpc_init_syntaxes(table, p->conn->flags,
					 &syntax, &transfer_syntax);
	if (!NT_STATUS_IS_OK(c->status)) {
		DEBUG(2,("Invalid uuid string in "
			 "dcerpc_bind_auth_none_send\n"));
		composite_error(c, c->status);
		return c;
	}

	/* c was only allocated as a container for a possible error */
	talloc_free(c);

	return dcerpc_bind_send(p, mem_ctx, &syntax, &transfer_syntax);
}
Пример #4
0
_PUBLIC_ bool composite_is_ok(struct composite_context *ctx)
{
	if (NT_STATUS_IS_OK(ctx->status)) {
		return true;
	}
	composite_error(ctx, ctx->status);
	return false;
}
Пример #5
0
_PUBLIC_ bool composite_nomem(const void *p, struct composite_context *ctx)
{
	if (p != NULL) {
		return false;
	}
	composite_error(ctx, NT_STATUS_NO_MEMORY);
	return true;
}
Пример #6
0
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;
}
Пример #7
0
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);
}
Пример #8
0
/*
  Receive an alter reply from the transport
*/
static void dcerpc_alter_recv_handler(struct rpc_request *req,
				      DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
{
	struct composite_context *c;
	struct dcerpc_pipe *recv_pipe;

	c = talloc_get_type(req->async.private_data, struct composite_context);
	recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);

	if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
	    pkt->u.alter_resp.num_results == 1 &&
	    pkt->u.alter_resp.ctx_list[0].result != 0) {
		DEBUG(2,("dcerpc: alter_resp failed - reason %d\n", 
			 pkt->u.alter_resp.ctx_list[0].reason));
		composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
		return;
	}

	if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
	    pkt->u.alter_resp.num_results == 0 ||
	    pkt->u.alter_resp.ctx_list[0].result != 0) {
		composite_error(c, NT_STATUS_NET_WRITE_FAULT);
		return;
	}

	/* the alter_resp might contain a reply set of credentials */
	if (recv_pipe->conn->security_state.auth_info &&
	    pkt->u.alter_resp.auth_info.length) {
		enum ndr_err_code ndr_err;
		ndr_err = ndr_pull_struct_blob(
			&pkt->u.alter_resp.auth_info, recv_pipe,
			NULL,
			recv_pipe->conn->security_state.auth_info,
			(ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			c->status = ndr_map_error2ntstatus(ndr_err);
			if (!composite_is_ok(c)) return;
		}
	}

	composite_done(c);
}
Пример #9
0
static void unbecomeDC_drsuapi_remove_ds_server_recv(struct rpc_request *req)
{
	struct libnet_UnbecomeDC_state *s = talloc_get_type(req->async.private_data,
					    struct libnet_UnbecomeDC_state);
	struct composite_context *c = s->creq;
	struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r;

	c->status = dcerpc_ndr_request_recv(req);
	if (!composite_is_ok(c)) return;

	if (!W_ERROR_IS_OK(r->out.result)) {
		composite_error(c, werror_to_ntstatus(r->out.result));
		return;
	}

	if (*r->out.level_out != 1) {
		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
		return;
	}

	composite_done(c);
}
Пример #10
0
_PUBLIC_ void composite_continue_smb2(struct composite_context *ctx,
				      struct smb2_request *new_req,
				      void (*continuation)(struct smb2_request *),
				      void *private_data)
{
	if (composite_nomem(new_req, ctx)) return;
	if (new_req->state > SMB2_REQUEST_RECV) {
		composite_error(ctx, new_req->status);
		return;
	}
	new_req->async.fn = continuation;
	new_req->async.private_data = private_data;
}
Пример #11
0
static void unbecomeDC_drsuapi_remove_ds_server_recv(struct tevent_req *subreq)
{
	struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(subreq,
					    struct libnet_UnbecomeDC_state);
	struct composite_context *c = s->creq;
	struct drsuapi_DsRemoveDSServer *r = &s->drsuapi.rm_ds_srv_r;

	c->status = dcerpc_drsuapi_DsRemoveDSServer_r_recv(subreq, s);
	TALLOC_FREE(subreq);
	if (!composite_is_ok(c)) return;

	if (!W_ERROR_IS_OK(r->out.result)) {
		composite_error(c, werror_to_ntstatus(r->out.result));
		return;
	}

	if (*r->out.level_out != 1) {
		composite_error(c, NT_STATUS_INVALID_NETWORK_RESPONSE);
		return;
	}

	composite_done(c);
}
Пример #12
0
/*
  composite session setup function that hides the details of all the
  different session setup varients, including the multi-pass nature of
  the spnego varient
*/
struct composite_context *smb_composite_sesssetup_send(struct smbcli_session *session, 
						       struct smb_composite_sesssetup *io)
{
	struct composite_context *c;
	struct sesssetup_state *state;
	NTSTATUS status;

	c = composite_create(session, session->transport->ev);
	if (c == NULL) return NULL;

	state = talloc_zero(c, struct sesssetup_state);
	if (composite_nomem(state, c)) return c;
	c->private_data = state;

	state->io = io;

	talloc_set_destructor(state, sesssetup_state_destructor);

	/* no session setup at all in earliest protocol varients */
	if (session->transport->negotiate.protocol < PROTOCOL_LANMAN1) {
		ZERO_STRUCT(io->out);
		composite_done(c);
		return c;
	}

	/* see what session setup interface we will use */
	if (session->transport->negotiate.protocol < PROTOCOL_NT1) {
		status = session_setup_old(c, session, io, &state->req);
	} else if (!session->transport->options.use_spnego ||
		   !(io->in.capabilities & CAP_EXTENDED_SECURITY)) {
		status = session_setup_nt1(c, session, io, &state->req);
	} else {
		status = session_setup_spnego(c, session, io, &state->req);
	}

	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) || 
	    NT_STATUS_IS_OK(status)) {
		composite_continue_smb(c, state->req, request_handler, c);	
		return c;
	}

	composite_error(c, status);
	return c;
}
Пример #13
0
static void unbecomeDC_drsuapi_bind_recv(struct tevent_req *subreq)
{
	struct libnet_UnbecomeDC_state *s = tevent_req_callback_data(subreq,
					    struct libnet_UnbecomeDC_state);
	struct composite_context *c = s->creq;

	c->status = dcerpc_drsuapi_DsBind_r_recv(subreq, s);
	TALLOC_FREE(subreq);
	if (!composite_is_ok(c)) return;

	if (!W_ERROR_IS_OK(s->drsuapi.bind_r.out.result)) {
		composite_error(c, werror_to_ntstatus(s->drsuapi.bind_r.out.result));
		return;
	}

	ZERO_STRUCT(s->drsuapi.remote_info28);
	if (s->drsuapi.bind_r.out.bind_info) {
		switch (s->drsuapi.bind_r.out.bind_info->length) {
		case 24: {
			struct drsuapi_DsBindInfo24 *info24;
			info24 = &s->drsuapi.bind_r.out.bind_info->info.info24;
			s->drsuapi.remote_info28.supported_extensions	= info24->supported_extensions;
			s->drsuapi.remote_info28.site_guid		= info24->site_guid;
			s->drsuapi.remote_info28.pid			= info24->pid;
			s->drsuapi.remote_info28.repl_epoch		= 0;
			break;
		}
		case 48: {
			struct drsuapi_DsBindInfo48 *info48;
			info48 = &s->drsuapi.bind_r.out.bind_info->info.info48;
			s->drsuapi.remote_info28.supported_extensions	= info48->supported_extensions;
			s->drsuapi.remote_info28.site_guid		= info48->site_guid;
			s->drsuapi.remote_info28.pid			= info48->pid;
			s->drsuapi.remote_info28.repl_epoch		= info48->repl_epoch;
			break;
		}
		case 28:
			s->drsuapi.remote_info28 = s->drsuapi.bind_r.out.bind_info->info.info28;
			break;
		}
	}

	unbecomeDC_drsuapi_remove_ds_server_send(s);
}
Пример #14
0
/*
  a bind or alter context has failed
*/
static void dcerpc_composite_fail(struct rpc_request *req)
{
	struct composite_context *c = talloc_get_type(req->async.private_data, 
						      struct composite_context);
	composite_error(c, req->status);
}
Пример #15
0
/*
  handler for completion of a smbcli_request sub-request
*/
static void request_handler(struct smbcli_request *req)
{
	struct composite_context *c = (struct composite_context *)req->async.private_data;
	struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
	struct smbcli_session *session = req->session;
	DATA_BLOB null_data_blob = data_blob(NULL, 0);
	NTSTATUS session_key_err, nt_status;
	struct smbcli_request *check_req = NULL;
	const char *os = NULL;
	const char *lanman = NULL;

	if (req->sign_caller_checks) {
		req->do_not_free = true;
		check_req = req;
	}

	state->remote_status = smb_raw_sesssetup_recv(req, state, &state->setup);
	c->status = state->remote_status;
	state->req = NULL;

	/*
	 * we only need to check the signature if the
	 * NT_STATUS_OK is returned
	 */
	if (!NT_STATUS_IS_OK(state->remote_status)) {
		talloc_free(check_req);
		check_req = NULL;
	}

	switch (state->setup.old.level) {
	case RAW_SESSSETUP_OLD:
		state->io->out.vuid = state->setup.old.out.vuid;
		/* This doesn't work, as this only happens on old
		 * protocols, where this comparison won't match. */
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			/* we neet to reset the vuid for a new try */
			session->vuid = 0;
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_old(c, session, 
							      state->io, 
							      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		os = state->setup.old.out.os;
		lanman = state->setup.old.out.lanman;
		break;

	case RAW_SESSSETUP_NT1:
		state->io->out.vuid = state->setup.nt1.out.vuid;
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			/* we need to reset the vuid for a new try */
			session->vuid = 0;
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_nt1(c, session, 
							      state->io, 
							      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		os = state->setup.nt1.out.os;
		lanman = state->setup.nt1.out.lanman;
		break;

	case RAW_SESSSETUP_SPNEGO:
		state->io->out.vuid = state->setup.spnego.out.vuid;
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			const char *principal;

			/* we need to reset the vuid for a new try */
			session->vuid = 0;

			principal = gensec_get_target_principal(session->gensec);
			if (principal == NULL) {
				const char *hostname = gensec_get_target_hostname(session->gensec);
				const char *service  = gensec_get_target_service(session->gensec);
				if (hostname != NULL && service != NULL) {
					principal = talloc_asprintf(state, "%s/%s", service, hostname);
				}
			}
			if (cli_credentials_failed_kerberos_login(state->io->in.credentials, principal, &state->logon_retries) ||
			    cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_spnego(c, session, 
								      state->io, 
								      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
		    !NT_STATUS_IS_OK(c->status)) {
			break;
		}
		if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {

			/* The status value here, from the earlier pass at GENSEC is
			 * vital to the security of the system.  Even if the other end
			 * accepts, if GENSEC claims 'MORE_PROCESSING_REQUIRED' then
			 * you must keep feeding it blobs, or else the remote
			 * host/attacker might avoid mutal authentication
			 * requirements */
			
			state->gensec_status = gensec_update(session->gensec, state, c->event_ctx,
							 state->setup.spnego.out.secblob,
							 &state->setup.spnego.in.secblob);
			c->status = state->gensec_status;
			if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
			    !NT_STATUS_IS_OK(c->status)) {
				break;
			}
		} else {
			state->setup.spnego.in.secblob = data_blob(NULL, 0);
		}

		if (NT_STATUS_IS_OK(state->remote_status)) {
			DATA_BLOB session_key;

			if (state->setup.spnego.in.secblob.length) {
				c->status = NT_STATUS_INTERNAL_ERROR;
				break;
			}
			session_key_err = gensec_session_key(session->gensec, session, &session_key);
			if (NT_STATUS_IS_OK(session_key_err)) {
				smb1cli_conn_activate_signing(session->transport->conn,
							      session_key,
							      null_data_blob);
			}

			c->status = smb1cli_session_set_session_key(session->smbXcli,
								    session_key);
			data_blob_free(&session_key);
			if (!NT_STATUS_IS_OK(c->status)) {
				break;
			}
		}

		if (state->setup.spnego.in.secblob.length) {
			/* 
			 * set the session->vuid value only for calling
			 * smb_raw_sesssetup_send()
			 */
			uint16_t vuid = session->vuid;
			session->vuid = state->io->out.vuid;
			state->req = smb_raw_sesssetup_send(session, &state->setup);
			session->vuid = vuid;
			if (state->req &&
			    !smb1cli_conn_signing_is_active(state->req->transport->conn)) {
				state->req->sign_caller_checks = true;
			}
			composite_continue_smb(c, state->req, request_handler, c);
			return;
		}
		os = state->setup.spnego.out.os;
		lanman = state->setup.spnego.out.lanman;
		break;

	case RAW_SESSSETUP_SMB2:
		c->status = NT_STATUS_INTERNAL_ERROR;
		break;
	}

	if (check_req) {
		bool ok;

		check_req->sign_caller_checks = false;

		ok = smb1cli_conn_check_signing(check_req->transport->conn,
						check_req->in.buffer, 1);
		if (!ok) {
			c->status = NT_STATUS_ACCESS_DENIED;
		}
		talloc_free(check_req);
		check_req = NULL;
	}

	if (!NT_STATUS_IS_OK(c->status)) {
		composite_error(c, c->status);
		return;
	}

	if (os) {
		session->os = talloc_strdup(session, os);
		if (composite_nomem(session->os, c)) return;
	} else {
		session->os = NULL;
	}
	if (lanman) {
		session->lanman = talloc_strdup(session, lanman);
		if (composite_nomem(session->lanman, c)) return;
	} else {
		session->lanman = NULL;
	}

	composite_done(c);
}
Пример #16
0
/*
  handler for completion of a smbcli_request sub-request
*/
static void request_handler(struct smbcli_request *req)
{
	struct composite_context *c = (struct composite_context *)req->async.private_data;
	struct sesssetup_state *state = talloc_get_type(c->private_data, struct sesssetup_state);
	struct smbcli_session *session = req->session;
	DATA_BLOB session_key = data_blob(NULL, 0);
	DATA_BLOB null_data_blob = data_blob(NULL, 0);
	NTSTATUS session_key_err, nt_status;
	struct smbcli_request *check_req = NULL;
	const char *os = NULL;
	const char *lanman = NULL;

	if (req->sign_caller_checks) {
		req->do_not_free = true;
		check_req = req;
	}

	state->remote_status = smb_raw_sesssetup_recv(req, state, &state->setup);
	c->status = state->remote_status;
	state->req = NULL;

	/*
	 * we only need to check the signature if the
	 * NT_STATUS_OK is returned
	 */
	if (!NT_STATUS_IS_OK(state->remote_status)) {
		talloc_free(check_req);
		check_req = NULL;
	}

	switch (state->setup.old.level) {
	case RAW_SESSSETUP_OLD:
		state->io->out.vuid = state->setup.old.out.vuid;
		/* This doesn't work, as this only happens on old
		 * protocols, where this comparison won't match. */
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			/* we neet to reset the vuid for a new try */
			session->vuid = 0;
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_old(c, session, 
							      state->io, 
							      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		os = state->setup.old.out.os;
		lanman = state->setup.old.out.lanman;
		break;

	case RAW_SESSSETUP_NT1:
		state->io->out.vuid = state->setup.nt1.out.vuid;
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			/* we neet to reset the vuid for a new try */
			session->vuid = 0;
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_nt1(c, session, 
							      state->io, 
							      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		os = state->setup.nt1.out.os;
		lanman = state->setup.nt1.out.lanman;
		break;

	case RAW_SESSSETUP_SPNEGO:
		state->io->out.vuid = state->setup.spnego.out.vuid;
		if (NT_STATUS_EQUAL(c->status, NT_STATUS_LOGON_FAILURE)) {
			/* we need to reset the vuid for a new try */
			session->vuid = 0;
			if (cli_credentials_wrong_password(state->io->in.credentials)) {
				nt_status = session_setup_spnego(c, session, 
								      state->io, 
								      &state->req);
				if (NT_STATUS_IS_OK(nt_status)) {
					talloc_free(check_req);
					c->status = nt_status;
					composite_continue_smb(c, state->req, request_handler, c);
					return;
				}
			}
		}
		if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
		    !NT_STATUS_IS_OK(c->status)) {
			break;
		}
		if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {

			/* The status value here, from the earlier pass at GENSEC is
			 * vital to the security of the system.  Even if the other end
			 * accepts, if GENSEC claims 'MORE_PROCESSING_REQUIRED' then
			 * you must keep feeding it blobs, or else the remote
			 * host/attacker might avoid mutal authentication
			 * requirements */
			
			state->gensec_status = gensec_update(session->gensec, state,
							 state->setup.spnego.out.secblob,
							 &state->setup.spnego.in.secblob);
			c->status = state->gensec_status;
			if (!NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
			    !NT_STATUS_IS_OK(c->status)) {
				break;
			}
		} else {
			state->setup.spnego.in.secblob = data_blob(NULL, 0);
		}

		if (NT_STATUS_IS_OK(state->remote_status)) {
			if (state->setup.spnego.in.secblob.length) {
				c->status = NT_STATUS_INTERNAL_ERROR;
				break;
			}
			session_key_err = gensec_session_key(session->gensec, session, &session->user_session_key);
			if (NT_STATUS_IS_OK(session_key_err)) {
				smbcli_transport_simple_set_signing(session->transport, session->user_session_key, null_data_blob);
			}
		}

		if (state->setup.spnego.in.secblob.length) {
			/* 
			 * set the session->vuid value only for calling
			 * smb_raw_sesssetup_send()
			 */
			uint16_t vuid = session->vuid;
			session->vuid = state->io->out.vuid;
			state->req = smb_raw_sesssetup_send(session, &state->setup);
			session->vuid = vuid;
			if (state->req) {
				state->req->sign_caller_checks = true;
			}
			composite_continue_smb(c, state->req, request_handler, c);
			return;
		}
		os = state->setup.spnego.out.os;
		lanman = state->setup.spnego.out.lanman;
		break;

	case RAW_SESSSETUP_SMB2:
		c->status = NT_STATUS_INTERNAL_ERROR;
		break;
	}

	if (check_req) {
		check_req->sign_caller_checks = false;
		if (!smbcli_request_check_sign_mac(check_req)) {
			c->status = NT_STATUS_ACCESS_DENIED;
		}
		talloc_free(check_req);
		check_req = NULL;
	}

	/* enforce the local signing required flag */
	if (NT_STATUS_IS_OK(c->status) && !cli_credentials_is_anonymous(state->io->in.credentials)) {
		if (!session->transport->negotiate.sign_info.doing_signing 
		    && session->transport->negotiate.sign_info.mandatory_signing) {
			DEBUG(0, ("SMB signing required, but server does not support it\n"));
			c->status = NT_STATUS_ACCESS_DENIED;
		}
	}

	if (!NT_STATUS_IS_OK(c->status)) {
		composite_error(c, c->status);
		return;
	}

	if (os) {
		session->os = talloc_strdup(session, os);
		if (composite_nomem(session->os, c)) return;
	} else {
		session->os = NULL;
	}
	if (lanman) {
		session->lanman = talloc_strdup(session, lanman);
		if (composite_nomem(session->lanman, c)) return;
	} else {
		session->lanman = NULL;
	}

	composite_done(c);
}