Example #1
0
static void smbd_smb2_read_pipe_done(struct tevent_req *subreq)
{
	struct tevent_req *req = tevent_req_callback_data(subreq,
				 struct tevent_req);
	struct smbd_smb2_read_state *state = tevent_req_data(req,
					     struct smbd_smb2_read_state);
	NTSTATUS status;
	ssize_t nread = -1;
	bool is_data_outstanding;

	status = np_read_recv(subreq, &nread, &is_data_outstanding);
	TALLOC_FREE(subreq);
	if (!NT_STATUS_IS_OK(status)) {
		tevent_req_nterror(req, status);
		return;
	}

	if (nread == 0 && state->out_data.length != 0) {
		tevent_req_nterror(req, NT_STATUS_END_OF_FILE);
		return;
	}

	state->out_data.length = nread;
	state->out_remaining = 0;

	/*
	 * TODO: add STATUS_BUFFER_OVERFLOW handling, once we also
	 * handle it in SMB1 pipe_read_andx_done().
	 */

	tevent_req_done(req);
}
Example #2
0
static void smbd_smb2_ioctl_pipe_read_done(struct tevent_req *subreq)
{
	struct tevent_req *req = tevent_req_callback_data(subreq,
				 struct tevent_req);
	struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
					      struct smbd_smb2_ioctl_state);
	NTSTATUS status;
	ssize_t nread = -1;
	bool is_data_outstanding = false;

	status = np_read_recv(subreq, &nread, &is_data_outstanding);

	DEBUG(10,("smbd_smb2_ioctl_pipe_read_done: np_read_recv nread = %d "
		 "is_data_outstanding = %d, status = %s\n",
		(int)nread,
		(int)is_data_outstanding,
		nt_errstr(status) ));

	TALLOC_FREE(subreq);
	if (!NT_STATUS_IS_OK(status)) {
		tevent_req_nterror(req, status);
		return;
	}

	state->out_output.length = nread;

	if (is_data_outstanding) {
		tevent_req_nterror(req, STATUS_BUFFER_OVERFLOW);
		return;
	}

	tevent_req_done(req);
}
Example #3
0
struct tevent_req *smb2_ioctl_dfs(uint32_t ctl_code,
				  struct tevent_context *ev,
				  struct tevent_req *req,
				  struct smbd_smb2_ioctl_state *state)
{
	NTSTATUS status;

	switch (ctl_code) {
	case FSCTL_DFS_GET_REFERRALS:
		status = fsctl_dfs_get_refers(state, ev, state->smbreq->conn,
					      &state->in_input,
					      state->in_max_output,
					      &state->out_output);
		if (!tevent_req_nterror(req, status)) {
			tevent_req_done(req);
		}
		return tevent_req_post(req, ev);
		break;
	default: {
		uint8_t *out_data = NULL;
		uint32_t out_data_len = 0;

		if (state->fsp == NULL) {
			status = NT_STATUS_NOT_SUPPORTED;
		} else {
			status = SMB_VFS_FSCTL(state->fsp,
					       state,
					       ctl_code,
					       state->smbreq->flags2,
					       state->in_input.data,
					       state->in_input.length,
					       &out_data,
					       state->in_max_output,
					       &out_data_len);
			state->out_output = data_blob_const(out_data, out_data_len);
			if (NT_STATUS_IS_OK(status)) {
				tevent_req_done(req);
				return tevent_req_post(req, ev);
			}
		}

		if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
			if (IS_IPC(state->smbreq->conn)) {
				status = NT_STATUS_FS_DRIVER_REQUIRED;
			} else {
				status = NT_STATUS_INVALID_DEVICE_REQUEST;
			}
		}

		tevent_req_nterror(req, status);
		return tevent_req_post(req, ev);
		break;
	}
	}

	tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
	return tevent_req_post(req, ev);
}
Example #4
0
static void open_socket_out_connected(struct tevent_req *subreq)
{
	struct tevent_req *req =
		tevent_req_callback_data(subreq, struct tevent_req);
	struct open_socket_out_state *state =
		tevent_req_data(req, struct open_socket_out_state);
	int ret;
	int sys_errno;

	ret = async_connect_recv(subreq, &sys_errno);
	TALLOC_FREE(subreq);
	if (ret == 0) {
		tevent_req_done(req);
		return;
	}

	if (
#ifdef ETIMEDOUT
		(sys_errno == ETIMEDOUT) ||
#endif
		(sys_errno == EINPROGRESS) ||
		(sys_errno == EALREADY) ||
		(sys_errno == EAGAIN)) {

		/*
		 * retry
		 */

		if (state->wait_usec < 250000) {
			state->wait_usec *= 1.5;
		}

		subreq = async_connect_send(state, state->ev, state->fd,
					    (struct sockaddr *)&state->ss,
					    state->salen);
		if (tevent_req_nomem(subreq, req)) {
			return;
		}
		if (!tevent_req_set_endtime(
			    subreq, state->ev,
			    timeval_current_ofs_usec(state->wait_usec))) {
			tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
			return;
		}
		tevent_req_set_callback(subreq, open_socket_out_connected, req);
		return;
	}

#ifdef EISCONN
	if (sys_errno == EISCONN) {
		tevent_req_done(req);
		return;
	}
#endif

	/* real error */
	tevent_req_nterror(req, map_nt_error_from_unix(sys_errno));
}
Example #5
0
static void wb_next_pwent_fill_done(struct tevent_req *subreq)
{
	struct tevent_req *req = tevent_req_callback_data(
		subreq, struct tevent_req);
	struct wb_next_pwent_state *state = tevent_req_data(
		req, struct wb_next_pwent_state);
	NTSTATUS status;

	status = wb_fill_pwent_recv(subreq);
	TALLOC_FREE(subreq);
	/*
	 * When you try to enumerate users with 'getent passwd' and the user
	 * doesn't have a uid set we should just move on.
	 */
	if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
		state->gstate->next_user += 1;

		if (state->gstate->next_user >= state->gstate->num_users) {
			TALLOC_FREE(state->gstate->users);

			state->gstate->domain = wb_next_find_domain(state->gstate->domain);
			if (state->gstate->domain == NULL) {
				tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES);
				return;
			}

			subreq = wb_query_user_list_send(state, state->ev,
					state->gstate->domain);
			if (tevent_req_nomem(subreq, req)) {
				return;
			}
			tevent_req_set_callback(subreq, wb_next_pwent_fetch_done, req);
			return;
		}

		subreq = wb_fill_pwent_send(state,
					    state->ev,
					    &state->gstate->users[state->gstate->next_user],
					    state->pw);
		if (tevent_req_nomem(subreq, req)) {
			return;
		}
		tevent_req_set_callback(subreq, wb_next_pwent_fill_done, req);

		return;
	} else if (tevent_req_nterror(req, status)) {
		return;
	}
	state->gstate->next_user += 1;
	tevent_req_done(req);
}
Example #6
0
static void smb2_ipc_getinfo(struct tevent_req *req,
				struct smbd_smb2_getinfo_state *state,
				struct tevent_context *ev,
				uint8_t in_info_type,
				uint8_t in_file_info_class)
{
	/* We want to reply to SMB2_GETINFO_FILE
	   with a class of SMB2_FILE_STANDARD_INFO as
	   otherwise a Win7 client issues this request
	   twice (2xroundtrips) if we return NOT_SUPPORTED.
	   NB. We do the same for SMB1 in call_trans2qpipeinfo() */

	if (in_info_type == 0x01 && /* SMB2_GETINFO_FILE */
			in_file_info_class == 0x05) { /* SMB2_FILE_STANDARD_INFO */
		state->out_output_buffer = data_blob_talloc(state,
						NULL, 24);
		if (tevent_req_nomem(state->out_output_buffer.data, req)) {
			return;
		}

		memset(state->out_output_buffer.data,0,24);
		SOFF_T(state->out_output_buffer.data,0,4096LL);
		SIVAL(state->out_output_buffer.data,16,1);
		SIVAL(state->out_output_buffer.data,20,1);
		tevent_req_done(req);
	} else {
		tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
	}
}
Example #7
0
static void smbd_smb2_ioctl_pipe_write_done(struct tevent_req *subreq)
{
	struct tevent_req *req = tevent_req_callback_data(subreq,
				 struct tevent_req);
	struct smbd_smb2_ioctl_state *state = tevent_req_data(req,
					      struct smbd_smb2_ioctl_state);
	NTSTATUS status;
	ssize_t nwritten = -1;

	status = np_write_recv(subreq, &nwritten);

	DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: received %ld\n",
		(long int)nwritten ));

	TALLOC_FREE(subreq);
	if (!NT_STATUS_IS_OK(status)) {
		tevent_req_nterror(req, status);
		return;
	}

	if (nwritten != state->in_input.length) {
		tevent_req_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE);
		return;
	}

	state->out_output = data_blob_talloc(state, NULL, state->in_max_output);
	if (state->in_max_output > 0 &&
	    tevent_req_nomem(state->out_output.data, req)) {
		return;
	}

	DEBUG(10,("smbd_smb2_ioctl_pipe_write_done: issuing np_read_send "
		"of size %u\n",
		(unsigned int)state->out_output.length ));

	subreq = np_read_send(state->smbreq->conn,
			      state->smb2req->sconn->ev_ctx,
			      state->fsp->fake_file_handle,
			      state->out_output.data,
			      state->out_output.length);
	if (tevent_req_nomem(subreq, req)) {
		return;
	}
	tevent_req_set_callback(subreq, smbd_smb2_ioctl_pipe_read_done, req);
}
Example #8
0
static void wb_next_pwent_fetch_done(struct tevent_req *subreq)
{
	struct tevent_req *req = tevent_req_callback_data(
		subreq, struct tevent_req);
	struct wb_next_pwent_state *state = tevent_req_data(
		req, struct wb_next_pwent_state);
	NTSTATUS status;

	status = wb_query_user_list_recv(subreq, state->gstate,
					 &state->gstate->num_users,
					 &state->gstate->users);
	TALLOC_FREE(subreq);
	if (!NT_STATUS_IS_OK(status)) {
		/* Ignore errors here, just log it */
		DEBUG(10, ("query_user_list for domain %s returned %s\n",
			   state->gstate->domain->name,
			   nt_errstr(status)));
		state->gstate->num_users = 0;
	}

	if (state->gstate->num_users == 0) {
		state->gstate->domain = state->gstate->domain->next;

		if ((state->gstate->domain != NULL)
		    && sid_check_is_domain(&state->gstate->domain->sid)) {
			state->gstate->domain = state->gstate->domain->next;
		}

		if (state->gstate->domain == NULL) {
			tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES);
			return;
		}
		subreq = wb_query_user_list_send(state, state->ev,
						 state->gstate->domain);
		if (tevent_req_nomem(subreq, req)) {
			return;
		}
		tevent_req_set_callback(subreq, wb_next_pwent_fetch_done, req);
		return;
	}

	state->gstate->next_user = 0;

	subreq = wb_fill_pwent_send(
		state, state->ev,
		&state->gstate->users[state->gstate->next_user],
		state->pw);
	if (tevent_req_nomem(subreq, req)) {
		return;
	}
	tevent_req_set_callback(subreq, wb_next_pwent_fill_done, req);
}
Example #9
0
void tevent_req_simple_finish_ntstatus(struct tevent_req *subreq,
				       NTSTATUS subreq_status)
{
	struct tevent_req *req = tevent_req_callback_data(
		subreq, struct tevent_req);

	TALLOC_FREE(subreq);

	if (!NT_STATUS_IS_OK(subreq_status)) {
		tevent_req_nterror(req, subreq_status);
		return;
	}
	tevent_req_done(req);
}
Example #10
0
static void smbd_smb2_notify_reply_trigger(struct tevent_context *ctx,
					   struct tevent_immediate *im,
					   void *private_data)
{
	struct tevent_req *req = talloc_get_type_abort(private_data,
						       struct tevent_req);
	struct smbd_smb2_notify_state *state = tevent_req_data(req,
					       struct smbd_smb2_notify_state);

	if (!NT_STATUS_IS_OK(state->status)) {
		tevent_req_nterror(req, state->status);
		return;
	}

	tevent_req_done(req);
}
Example #11
0
struct tevent_req *wb_next_pwent_send(TALLOC_CTX *mem_ctx,
				      struct tevent_context *ev,
				      struct getpwent_state *gstate,
				      struct winbindd_pw *pw)
{
	struct tevent_req *req, *subreq;
	struct wb_next_pwent_state *state;

	req = tevent_req_create(mem_ctx, &state, struct wb_next_pwent_state);
	if (req == NULL) {
		return NULL;
	}
	state->ev = ev;
	state->gstate = gstate;
	state->pw = pw;

	if (state->gstate->next_user >= state->gstate->num_users) {
		TALLOC_FREE(state->gstate->users);

		state->gstate->domain = wb_next_find_domain(state->gstate->domain);
		if (state->gstate->domain == NULL) {
			tevent_req_nterror(req, NT_STATUS_NO_MORE_ENTRIES);
			return tevent_req_post(req, ev);
		}
		subreq = wb_query_user_list_send(state, state->ev,
						 state->gstate->domain);
		if (tevent_req_nomem(subreq, req)) {
			return tevent_req_post(req, ev);
		}
		tevent_req_set_callback(subreq, wb_next_pwent_fetch_done, req);
		return req;
	}

	subreq = wb_fill_pwent_send(
		state, state->ev,
		&state->gstate->users[state->gstate->next_user],
		state->pw);
	if (tevent_req_nomem(subreq, req)) {
		return tevent_req_post(req, ev);
	}
	tevent_req_set_callback(subreq, wb_next_pwent_fill_done, req);
	return req;
}
Example #12
0
static void smbd_smb2_notify_reply(struct smb_request *smbreq,
				   NTSTATUS error_code,
				   uint8_t *buf, size_t len)
{
	struct tevent_req *req = talloc_get_type_abort(smbreq->async_priv,
						       struct tevent_req);
	struct smbd_smb2_notify_state *state = tevent_req_data(req,
					       struct smbd_smb2_notify_state);

	if (state->skip_reply) {
		return;
	}

	SMBPROFILE_IOBYTES_ASYNC_SET_BUSY(state->smb2req->profile);

	state->status = error_code;
	if (!NT_STATUS_IS_OK(error_code)) {
		/* nothing */
	} else if (len == 0) {
		state->status = STATUS_NOTIFY_ENUM_DIR;
	} else {
		state->out_output_buffer = data_blob_talloc(state, buf, len);
		if (state->out_output_buffer.data == NULL) {
			state->status = NT_STATUS_NO_MEMORY;
		}
	}

	tevent_req_defer_callback(req, state->smb2req->sconn->ev_ctx);

	if (!NT_STATUS_IS_OK(state->status)) {
		tevent_req_nterror(req, state->status);
		return;
	}

	tevent_req_done(req);
}
Example #13
0
File: cldap.c Project: gojdic/samba
/*
  handle recv events on a cldap socket
*/
static void cldap_socket_recv_dgram(struct cldap_socket *c,
				    struct cldap_incoming *in)
{
	DATA_BLOB blob;
	struct asn1_data *asn1;
	void *p;
	struct cldap_search_state *search;
	NTSTATUS status;

	if (in->recv_errno != 0) {
		goto error;
	}

	blob = data_blob_const(in->buf, in->len);

	asn1 = asn1_init(in);
	if (!asn1) {
		goto nomem;
	}

	if (!asn1_load(asn1, blob)) {
		goto nomem;
	}

	in->ldap_msg = talloc(in, struct ldap_message);
	if (in->ldap_msg == NULL) {
		goto nomem;
	}

	/* this initial decode is used to find the message id */
	status = ldap_decode(asn1, NULL, in->ldap_msg);
	if (!NT_STATUS_IS_OK(status)) {
		goto nterror;
	}

	/* find the pending request */
	p = idr_find(c->searches.idr, in->ldap_msg->messageid);
	if (p == NULL) {
		if (!c->incoming.handler) {
			goto done;
		}

		/* this function should free or steal 'in' */
		c->incoming.handler(c, c->incoming.private_data, in);
		return;
	}

	search = talloc_get_type(p, struct cldap_search_state);
	search->response.in = talloc_move(search, &in);
	search->response.asn1 = asn1;
	search->response.asn1->ofs = 0;

	tevent_req_done(search->req);
	goto done;

nomem:
	in->recv_errno = ENOMEM;
error:
	status = map_nt_error_from_unix(in->recv_errno);
nterror:
	/* in connected mode the first pending search gets the error */
	if (!c->connected) {
		/* otherwise we just ignore the error */
		goto done;
	}
	if (!c->searches.list) {
		goto done;
	}
	tevent_req_nterror(c->searches.list->req, status);
done:
	talloc_free(in);
}
Example #14
0
static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx,
						struct tevent_context *ev,
						struct smbd_smb2_request *smb2req,
						struct files_struct *fsp,
						uint16_t in_flags,
						uint32_t in_output_buffer_length,
						uint64_t in_completion_filter)
{
	struct tevent_req *req;
	struct smbd_smb2_notify_state *state;
	struct smb_request *smbreq;
	connection_struct *conn = smb2req->tcon->compat;
	bool recursive = (in_flags & SMB2_WATCH_TREE) ? true : false;
	NTSTATUS status;

	req = tevent_req_create(mem_ctx, &state,
				struct smbd_smb2_notify_state);
	if (req == NULL) {
		return NULL;
	}
	state->smb2req = smb2req;
	state->status = NT_STATUS_INTERNAL_ERROR;
	state->out_output_buffer = data_blob_null;
	talloc_set_destructor(state, smbd_smb2_notify_state_destructor);

	DEBUG(10,("smbd_smb2_notify_send: %s - %s\n",
		  fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));

	smbreq = smbd_smb2_fake_smb_request(smb2req);
	if (tevent_req_nomem(smbreq, req)) {
		return tevent_req_post(req, ev);
	}

	state->smbreq = smbreq;
	smbreq->async_priv = (void *)req;

	if (DEBUGLEVEL >= 3) {
		char *filter_string;

		filter_string = notify_filter_string(NULL, in_completion_filter);
		if (tevent_req_nomem(filter_string, req)) {
			return tevent_req_post(req, ev);
		}

		DEBUG(3,("smbd_smb2_notify_send: notify change "
			 "called on %s, filter = %s, recursive = %d\n",
			 fsp_str_dbg(fsp), filter_string, recursive));

		TALLOC_FREE(filter_string);
	}

	if ((!fsp->is_directory) || (conn != fsp->conn)) {
		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return tevent_req_post(req, ev);
	}

	if (fsp->notify == NULL) {

		status = change_notify_create(fsp,
					      in_completion_filter,
					      recursive);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(10, ("change_notify_create returned %s\n",
				   nt_errstr(status)));
			tevent_req_nterror(req, status);
			return tevent_req_post(req, ev);
		}
	}

	if (change_notify_fsp_has_changes(fsp)) {

		/*
		 * We've got changes pending, respond immediately
		 */

		/*
		 * TODO: write a torture test to check the filtering behaviour
		 * here.
		 */

		change_notify_reply(smbreq,
				    NT_STATUS_OK,
				    in_output_buffer_length,
				    fsp->notify,
				    smbd_smb2_notify_reply);

		/*
		 * change_notify_reply() above has independently
		 * called tevent_req_done().
		 */
		return tevent_req_post(req, ev);
	}

	/*
	 * No changes pending, queue the request
	 */

	status = change_notify_add_request(smbreq,
			in_output_buffer_length,
			in_completion_filter,
			recursive, fsp,
			smbd_smb2_notify_reply);
	if (!NT_STATUS_IS_OK(status)) {
		tevent_req_nterror(req, status);
		return tevent_req_post(req, ev);
	}

	/*
	 * This is a HACK!
	 *
	 * change_notify_add_request() talloc_moves()
	 * smbreq away from us, so we need a destructor
	 * which moves it back at the end.
	 */
	state->has_request = true;
	talloc_set_destructor(smbreq, smbd_smb2_notify_smbreq_destructor);

	/* allow this request to be canceled */
	tevent_req_set_cancel_fn(req, smbd_smb2_notify_cancel);

	SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(state->smb2req->profile);
	return req;
}
static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx,
					      struct tevent_context *ev,
					      struct smbd_smb2_request *smb2req,
					      struct files_struct *fsp,
					      uint32_t in_length,
					      uint64_t in_offset,
					      uint32_t in_minimum,
					      uint32_t in_remaining)
{
	NTSTATUS status;
	struct tevent_req *req = NULL;
	struct smbd_smb2_read_state *state = NULL;
	struct smb_request *smbreq = NULL;
	connection_struct *conn = smb2req->tcon->compat;
	ssize_t nread = -1;
	struct lock_struct lock;
	int saved_errno;

	req = tevent_req_create(mem_ctx, &state,
				struct smbd_smb2_read_state);
	if (req == NULL) {
		return NULL;
	}
	state->smb2req = smb2req;
	state->in_length = in_length;
	state->in_offset = in_offset;
	state->in_minimum = in_minimum;
	state->out_data = data_blob_null;
	state->out_remaining = 0;

	DEBUG(10,("smbd_smb2_read: %s - %s\n",
		  fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));

	smbreq = smbd_smb2_fake_smb_request(smb2req);
	if (tevent_req_nomem(smbreq, req)) {
		return tevent_req_post(req, ev);
	}
	state->smbreq = smbreq;

	if (fsp->is_directory) {
		tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
		return tevent_req_post(req, ev);
	}

	state->fsp = fsp;

	if (IS_IPC(smbreq->conn)) {
		struct tevent_req *subreq = NULL;

		state->out_data = data_blob_talloc(state, NULL, in_length);
		if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
			return tevent_req_post(req, ev);
		}

		if (!fsp_is_np(fsp)) {
			tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
			return tevent_req_post(req, ev);
		}

		subreq = np_read_send(state, ev,
				      fsp->fake_file_handle,
				      state->out_data.data,
				      state->out_data.length);
		if (tevent_req_nomem(subreq, req)) {
			return tevent_req_post(req, ev);
		}
		tevent_req_set_callback(subreq,
					smbd_smb2_read_pipe_done,
					req);
		return req;
	}

	if (!CHECK_READ(fsp, smbreq)) {
		tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
		return tevent_req_post(req, ev);
	}

	status = schedule_smb2_aio_read(fsp->conn,
				smbreq,
				fsp,
				state,
				&state->out_data,
				(off_t)in_offset,
				(size_t)in_length);

	if (NT_STATUS_IS_OK(status)) {
		/*
		 * Doing an async read, allow this
		 * request to be canceled
		 */
		tevent_req_set_cancel_fn(req, smbd_smb2_read_cancel);
		return req;
	}

	if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
		/* Real error in setting up aio. Fail. */
		tevent_req_nterror(req, status);
		return tevent_req_post(req, ev);
	}

	/* Fallback to synchronous. */

	init_strict_lock_struct(fsp,
				fsp->op->global->open_persistent_id,
				in_offset,
				in_length,
				READ_LOCK,
				&lock);

	if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
		tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
		return tevent_req_post(req, ev);
	}

	/* Try sendfile in preference. */
	status = schedule_smb2_sendfile_read(smb2req, state);
	if (NT_STATUS_IS_OK(status)) {
		tevent_req_done(req);
		return tevent_req_post(req, ev);
	} else {
		if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
			SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
			tevent_req_nterror(req, status);
			return tevent_req_post(req, ev);
		}
	}

	/* Ok, read into memory. Allocate the out buffer. */
	state->out_data = data_blob_talloc(state, NULL, in_length);
	if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
		SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
		return tevent_req_post(req, ev);
	}

	nread = read_file(fsp,
			  (char *)state->out_data.data,
			  in_offset,
			  in_length);

	saved_errno = errno;

	SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);

	DEBUG(10,("smbd_smb2_read: file %s, %s, offset=%llu "
		"len=%llu returned %lld\n",
		fsp_str_dbg(fsp),
		fsp_fnum_dbg(fsp),
		(unsigned long long)in_offset,
		(unsigned long long)in_length,
		(long long)nread));

	status = smb2_read_complete(req, nread, saved_errno);
	if (!NT_STATUS_IS_OK(status)) {
		tevent_req_nterror(req, status);
	} else {
		/* Success. */
		tevent_req_done(req);
	}
	return tevent_req_post(req, ev);
}
Example #16
0
static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx,
					      struct tevent_context *ev,
					      struct smbd_smb2_request *smb2req,
					      uint32_t in_smbpid,
					      uint64_t in_file_id_volatile,
					      uint32_t in_length,
					      uint64_t in_offset,
					      uint32_t in_minimum,
					      uint32_t in_remaining)
{
	NTSTATUS status;
	struct tevent_req *req = NULL;
	struct smbd_smb2_read_state *state = NULL;
	struct smb_request *smbreq = NULL;
	connection_struct *conn = smb2req->tcon->compat_conn;
	files_struct *fsp = NULL;
	ssize_t nread = -1;
	struct lock_struct lock;
	int saved_errno;

	req = tevent_req_create(mem_ctx, &state,
				struct smbd_smb2_read_state);
	if (req == NULL) {
		return NULL;
	}
	state->smb2req = smb2req;
	state->in_length = in_length;
	state->in_offset = in_offset;
	state->in_minimum = in_minimum;
	state->out_data = data_blob_null;
	state->out_remaining = 0;

	DEBUG(10,("smbd_smb2_read: file_id[0x%016llX]\n",
		  (unsigned long long)in_file_id_volatile));

	smbreq = smbd_smb2_fake_smb_request(smb2req);
	if (tevent_req_nomem(smbreq, req)) {
		return tevent_req_post(req, ev);
	}

	fsp = file_fsp(smbreq, (uint16_t)in_file_id_volatile);
	if (fsp == NULL) {
		tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
		return tevent_req_post(req, ev);
	}
	if (conn != fsp->conn) {
		tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
		return tevent_req_post(req, ev);
	}
	if (smb2req->session->vuid != fsp->vuid) {
		tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
		return tevent_req_post(req, ev);
	}
	if (fsp->is_directory) {
		tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
		return tevent_req_post(req, ev);
	}

	state->fsp = fsp;
	state->in_file_id_volatile = in_file_id_volatile;

	if (IS_IPC(smbreq->conn)) {
		struct tevent_req *subreq = NULL;

		state->out_data = data_blob_talloc(state, NULL, in_length);
		if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
			return tevent_req_post(req, ev);
		}

		if (!fsp_is_np(fsp)) {
			tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
			return tevent_req_post(req, ev);
		}

		subreq = np_read_send(state, server_event_context(),
				      fsp->fake_file_handle,
				      state->out_data.data,
				      state->out_data.length);
		if (tevent_req_nomem(subreq, req)) {
			return tevent_req_post(req, ev);
		}
		tevent_req_set_callback(subreq,
					smbd_smb2_read_pipe_done,
					req);
		return req;
	}

	if (!CHECK_READ(fsp, smbreq)) {
		tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
		return tevent_req_post(req, ev);
	}

	status = schedule_smb2_aio_read(fsp->conn,
				smbreq,
				fsp,
				state,
				&state->out_data,
				(SMB_OFF_T)in_offset,
				(size_t)in_length);

	if (NT_STATUS_IS_OK(status)) {
		/*
		 * Doing an async read. Don't
		 * send a "gone async" message
		 * as we expect this to be less
		 * than the client timeout period.
		 * JRA. FIXME for offline files..
		 * FIXME. Add cancel code..
		 */
		smb2req->async = true;
		return req;
	}

	if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
		/* Real error in setting up aio. Fail. */
		tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
		return tevent_req_post(req, ev);
	}

	/* Fallback to synchronous. */

	init_strict_lock_struct(fsp,
				in_file_id_volatile,
				in_offset,
				in_length,
				READ_LOCK,
				&lock);

	if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
		tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
		return tevent_req_post(req, ev);
	}

	/* Try sendfile in preference. */
	status = schedule_smb2_sendfile_read(smb2req, state);
	if (NT_STATUS_IS_OK(status)) {
		tevent_req_done(req);
		return tevent_req_post(req, ev);
	} else {
		if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
			SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
			tevent_req_nterror(req, status);
			return tevent_req_post(req, ev);
		}
	}

	/* Ok, read into memory. Allocate the out buffer. */
	state->out_data = data_blob_talloc(state, NULL, in_length);
	if (in_length > 0 && tevent_req_nomem(state->out_data.data, req)) {
		SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
		return tevent_req_post(req, ev);
	}

	nread = read_file(fsp,
			  (char *)state->out_data.data,
			  in_offset,
			  in_length);

	saved_errno = errno;

	SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);

	DEBUG(10,("smbd_smb2_read: file %s handle [0x%016llX] offset=%llu "
		"len=%llu returned %lld\n",
		fsp_str_dbg(fsp),
		(unsigned long long)in_file_id_volatile,
		(unsigned long long)in_offset,
		(unsigned long long)in_length,
		(long long)nread));

	status = smb2_read_complete(req, nread, saved_errno);
	if (!NT_STATUS_IS_OK(status)) {
		tevent_req_nterror(req, status);
	} else {
		/* Success. */
		tevent_req_done(req);
	}
	return tevent_req_post(req, ev);
}
Example #17
0
struct tevent_req *smb2_ioctl_named_pipe(uint32_t ctl_code,
					 struct tevent_context *ev,
					 struct tevent_req *req,
					 struct smbd_smb2_ioctl_state *state)
{
	NTSTATUS status;
	uint8_t *out_data = NULL;
	uint32_t out_data_len = 0;

	if (ctl_code == FSCTL_PIPE_TRANSCEIVE) {
		struct tevent_req *subreq;

		if (!IS_IPC(state->smbreq->conn)) {
			tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
			return tevent_req_post(req, ev);
		}

		if (state->fsp == NULL) {
			tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
			return tevent_req_post(req, ev);
		}

		if (!fsp_is_np(state->fsp)) {
			tevent_req_nterror(req, NT_STATUS_FILE_CLOSED);
			return tevent_req_post(req, ev);
		}

		DEBUG(10,("smbd_smb2_ioctl_send: np_write_send of size %u\n",
			(unsigned int)state->in_input.length ));

		subreq = np_write_send(state, ev,
				       state->fsp->fake_file_handle,
				       state->in_input.data,
				       state->in_input.length);
		if (tevent_req_nomem(subreq, req)) {
			return tevent_req_post(req, ev);
		}
		tevent_req_set_callback(subreq,
					smbd_smb2_ioctl_pipe_write_done,
					req);
		return req;
	}

	if (state->fsp == NULL) {
		status = NT_STATUS_NOT_SUPPORTED;
	} else {
		status = SMB_VFS_FSCTL(state->fsp,
				       state,
				       ctl_code,
				       state->smbreq->flags2,
				       state->in_input.data,
				       state->in_input.length,
				       &out_data,
				       state->in_max_output,
				       &out_data_len);
		state->out_output = data_blob_const(out_data, out_data_len);
		if (NT_STATUS_IS_OK(status)) {
			tevent_req_done(req);
			return tevent_req_post(req, ev);
		}
	}

	if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
		if (IS_IPC(state->smbreq->conn)) {
			status = NT_STATUS_FS_DRIVER_REQUIRED;
		} else {
			status = NT_STATUS_INVALID_DEVICE_REQUEST;
		}
	}

	tevent_req_nterror(req, status);
	return tevent_req_post(req, ev);
}
Example #18
0
struct tevent_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
					struct event_context *ev,
					const struct sockaddr_storage *pss,
					uint16_t port,
					int timeout)
{
	char addr[INET6_ADDRSTRLEN];
	struct tevent_req *result, *subreq;
	struct open_socket_out_state *state;
	NTSTATUS status;

	result = tevent_req_create(mem_ctx, &state,
				   struct open_socket_out_state);
	if (result == NULL) {
		return NULL;
	}
	state->ev = ev;
	state->ss = *pss;
	state->port = port;
	state->wait_usec = 10000;
	state->salen = -1;

	state->fd = socket(state->ss.ss_family, SOCK_STREAM, 0);
	if (state->fd == -1) {
		status = map_nt_error_from_unix(errno);
		goto post_status;
	}
	talloc_set_destructor(state, open_socket_out_state_destructor);

	if (!tevent_req_set_endtime(
		    result, ev, timeval_current_ofs_msec(timeout))) {
		goto fail;
	}

#if defined(HAVE_IPV6)
	if (pss->ss_family == AF_INET6) {
		struct sockaddr_in6 *psa6;
		psa6 = (struct sockaddr_in6 *)&state->ss;
		psa6->sin6_port = htons(port);
		if (psa6->sin6_scope_id == 0
		    && IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) {
			setup_linklocal_scope_id(
				(struct sockaddr *)&(state->ss));
		}
		state->salen = sizeof(struct sockaddr_in6);
	}
#endif
	if (pss->ss_family == AF_INET) {
		struct sockaddr_in *psa;
		psa = (struct sockaddr_in *)&state->ss;
		psa->sin_port = htons(port);
		state->salen = sizeof(struct sockaddr_in);
	}

	if (pss->ss_family == AF_UNIX) {
		state->salen = sizeof(struct sockaddr_un);
	}

	print_sockaddr(addr, sizeof(addr), &state->ss);
	DEBUG(3,("Connecting to %s at port %u\n", addr,	(unsigned int)port));

	subreq = async_connect_send(state, state->ev, state->fd,
				    (struct sockaddr *)&state->ss,
				    state->salen);
	if ((subreq == NULL)
	    || !tevent_req_set_endtime(
		    subreq, state->ev,
		    timeval_current_ofs(0, state->wait_usec))) {
		goto fail;
	}
	tevent_req_set_callback(subreq, open_socket_out_connected, result);
	return result;

 post_status:
	tevent_req_nterror(result, status);
	return tevent_req_post(result, ev);
 fail:
	TALLOC_FREE(result);
	return NULL;
}
Example #19
0
static struct tevent_req *smbd_smb2_notify_send(TALLOC_CTX *mem_ctx,
						struct tevent_context *ev,
						struct smbd_smb2_request *smb2req,
						struct files_struct *fsp,
						uint16_t in_flags,
						uint32_t in_output_buffer_length,
						uint64_t in_completion_filter)
{
	struct tevent_req *req;
	struct smbd_smb2_notify_state *state;
	struct smb_request *smbreq;
	connection_struct *conn = smb2req->tcon->compat_conn;
	bool recursive = (in_flags & 0x0001) ? true : false;
	NTSTATUS status;

	req = tevent_req_create(mem_ctx, &state,
				struct smbd_smb2_notify_state);
	if (req == NULL) {
		return NULL;
	}
	state->smb2req = smb2req;
	state->status = NT_STATUS_INTERNAL_ERROR;
	state->out_output_buffer = data_blob_null;
	state->im = NULL;

	DEBUG(10,("smbd_smb2_notify_send: %s - fnum[%d]\n",
		  fsp_str_dbg(fsp), fsp->fnum));

	smbreq = smbd_smb2_fake_smb_request(smb2req);
	if (tevent_req_nomem(smbreq, req)) {
		return tevent_req_post(req, ev);
	}

	state->smbreq = smbreq;
	smbreq->async_priv = (void *)req;

	{
		char *filter_string;

		filter_string = notify_filter_string(NULL, in_completion_filter);
		if (tevent_req_nomem(filter_string, req)) {
			return tevent_req_post(req, ev);
		}

		DEBUG(3,("smbd_smb2_notify_send: notify change "
			 "called on %s, filter = %s, recursive = %d\n",
			 fsp_str_dbg(fsp), filter_string, recursive));

		TALLOC_FREE(filter_string);
	}

	if ((!fsp->is_directory) || (conn != fsp->conn)) {
		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return tevent_req_post(req, ev);
	}

	if (fsp->notify == NULL) {

		status = change_notify_create(fsp,
					      in_completion_filter,
					      recursive);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(10, ("change_notify_create returned %s\n",
				   nt_errstr(status)));
			tevent_req_nterror(req, status);
			return tevent_req_post(req, ev);
		}
	}

	if (fsp->notify->num_changes != 0) {

		/*
		 * We've got changes pending, respond immediately
		 */

		/*
		 * TODO: write a torture test to check the filtering behaviour
		 * here.
		 */

		change_notify_reply(smbreq,
				    NT_STATUS_OK,
				    in_output_buffer_length,
				    fsp->notify,
				    smbd_smb2_notify_reply);

		/*
		 * change_notify_reply() above has independently
		 * called tevent_req_done().
		 */
		return tevent_req_post(req, ev);
	}

	state->im = tevent_create_immediate(state);
	if (tevent_req_nomem(state->im, req)) {
		return tevent_req_post(req, ev);
	}

	/*
	 * No changes pending, queue the request
	 */

	status = change_notify_add_request(smbreq,
			in_output_buffer_length,
			in_completion_filter,
			recursive, fsp,
			smbd_smb2_notify_reply);
	if (!NT_STATUS_IS_OK(status)) {
		tevent_req_nterror(req, status);
		return tevent_req_post(req, ev);
	}

	/* allow this request to be canceled */
	tevent_req_set_cancel_fn(req, smbd_smb2_notify_cancel);

	return req;
}
Example #20
0
/*
  handle recv events on a cldap socket
*/
static bool cldap_socket_recv_dgram(struct cldap_socket *c,
				    struct cldap_incoming *in)
{
	DATA_BLOB blob;
	struct asn1_data *asn1;
	void *p;
	struct cldap_search_state *search;
	NTSTATUS status;

	if (in->recv_errno != 0) {
		goto error;
	}

	blob = data_blob_const(in->buf, in->len);

	asn1 = asn1_init(in);
	if (!asn1) {
		goto nomem;
	}

	if (!asn1_load(asn1, blob)) {
		goto nomem;
	}

	in->ldap_msg = talloc(in, struct ldap_message);
	if (in->ldap_msg == NULL) {
		goto nomem;
	}

	/* this initial decode is used to find the message id */
	status = ldap_decode(asn1, NULL, in->ldap_msg);
	if (!NT_STATUS_IS_OK(status)) {
		goto nterror;
	}

	/* find the pending request */
	p = idr_find(c->searches.idr, in->ldap_msg->messageid);
	if (p == NULL) {
		if (!c->incoming.handler) {
			TALLOC_FREE(in);
			return true;
		}

		/* this function should free or steal 'in' */
		c->incoming.handler(c, c->incoming.private_data, in);
		return false;
	}

	search = talloc_get_type_abort(p, struct cldap_search_state);
	search->response.in = talloc_move(search, &in);
	search->response.asn1 = asn1;
	search->response.asn1->ofs = 0;

	DLIST_REMOVE(c->searches.list, search);

	if (cldap_recvfrom_setup(c)) {
		tevent_req_done(search->req);
		return true;
	}

	/*
	 * This request was ok, just defer the notify of the caller
	 * and then just fail the next request if needed
	 */
	tevent_req_defer_callback(search->req, search->caller.ev);
	tevent_req_done(search->req);

	status = NT_STATUS_NO_MEMORY;
	/* in is NULL it this point */
	goto nterror;
nomem:
	in->recv_errno = ENOMEM;
error:
	status = map_nt_error_from_unix_common(in->recv_errno);
nterror:
	TALLOC_FREE(in);
	/* in connected mode the first pending search gets the error */
	if (!c->connected) {
		/* otherwise we just ignore the error */
		return false;
	}
	if (!c->searches.list) {
		return false;
	}
	/*
	 * We might called tevent_req_done() for a successful
	 * search before, so we better deliver the failure
	 * after the success, that is why we better also
	 * use tevent_req_defer_callback() here.
	 */
	tevent_req_defer_callback(c->searches.list->req,
				  c->searches.list->caller.ev);
	tevent_req_nterror(c->searches.list->req, status);
	return false;
}
Example #21
0
static void cli_trans_done(struct tevent_req *subreq)
{
	struct tevent_req *req = tevent_req_callback_data(
		subreq, struct tevent_req);
	struct cli_trans_state *state = tevent_req_data(
		req, struct cli_trans_state);
	NTSTATUS status;
	bool sent_all;
	uint8_t wct;
	uint16_t *vwv;
	uint32_t num_bytes;
	uint8_t *bytes;
	uint8_t num_setup	= 0;
	uint16_t *setup		= NULL;
	uint32_t total_param	= 0;
	uint32_t num_param	= 0;
	uint32_t param_disp	= 0;
	uint32_t total_data	= 0;
	uint32_t num_data	= 0;
	uint32_t data_disp	= 0;
	uint8_t *param		= NULL;
	uint8_t *data		= NULL;

	status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes);

	/*
	 * We can receive something like STATUS_MORE_ENTRIES, so don't use
	 * !NT_STATUS_IS_OK(status) here.
	 */

	if (NT_STATUS_IS_ERR(status)) {
		goto fail;
	}

	sent_all = ((state->param_sent == state->num_param)
		    && (state->data_sent == state->num_data));

	status = cli_pull_trans(
		cli_smb_inbuf(subreq), wct, vwv, num_bytes, bytes,
		state->cmd, !sent_all, &num_setup, &setup,
		&total_param, &num_param, &param_disp, &param,
		&total_data, &num_data, &data_disp, &data);

	if (!NT_STATUS_IS_OK(status)) {
		goto fail;
	}

	if (!sent_all) {
		int iov_count;

		TALLOC_FREE(subreq);

		cli_trans_format(state, &wct, &iov_count);

		subreq = cli_smb_req_create(state, state->ev, state->cli,
					    state->cmd + 1, 0, wct, state->vwv,
					    iov_count, state->iov);
		if (tevent_req_nomem(subreq, req)) {
			return;
		}
		cli_smb_req_set_mid(subreq, state->mid);

		if (!cli_smb_req_send(subreq)) {
			status = NT_STATUS_NO_MEMORY;
			goto fail;
		}
		tevent_req_set_callback(subreq, cli_trans_done, req);
		return;
	}

	status = cli_trans_pull_blob(
		state, &state->rparam, total_param, num_param, param,
		param_disp);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
		goto fail;
	}

	status = cli_trans_pull_blob(
		state, &state->rdata, total_data, num_data, data,
		data_disp);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
		goto fail;
	}

	if ((state->rparam.total == state->rparam.received)
	    && (state->rdata.total == state->rdata.received)) {
		TALLOC_FREE(subreq);
		cli_state_seqnum_remove(state->cli, state->mid);
		tevent_req_done(req);
		return;
	}

	if (!cli_smb_req_set_pending(subreq)) {
		status = NT_STATUS_NO_MEMORY;
		goto fail;
	}
	return;

 fail:
	cli_state_seqnum_remove(state->cli, state->mid);
	TALLOC_FREE(subreq);
	tevent_req_nterror(req, status);
}
Example #22
0
static struct tevent_req *smbd_smb2_getinfo_send(TALLOC_CTX *mem_ctx,
						 struct tevent_context *ev,
						 struct smbd_smb2_request *smb2req,
						 struct files_struct *fsp,
						 uint8_t in_info_type,
						 uint8_t in_file_info_class,
						 uint32_t in_output_buffer_length,
						 DATA_BLOB in_input_buffer,
						 uint32_t in_additional_information,
						 uint32_t in_flags)
{
	struct tevent_req *req;
	struct smbd_smb2_getinfo_state *state;
	struct smb_request *smbreq;
	connection_struct *conn = smb2req->tcon->compat;
	NTSTATUS status;

	req = tevent_req_create(mem_ctx, &state,
				struct smbd_smb2_getinfo_state);
	if (req == NULL) {
		return NULL;
	}
	state->smb2req = smb2req;
	state->status = NT_STATUS_OK;
	state->out_output_buffer = data_blob_null;

	DEBUG(10,("smbd_smb2_getinfo_send: %s - %s\n",
		  fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));

	smbreq = smbd_smb2_fake_smb_request(smb2req);
	if (tevent_req_nomem(smbreq, req)) {
		return tevent_req_post(req, ev);
	}

	if (IS_IPC(conn)) {
		smb2_ipc_getinfo(req, state, ev,
			in_info_type, in_file_info_class);
		return tevent_req_post(req, ev);
	}

	switch (in_info_type) {
	case SMB2_GETINFO_FILE:
	{
		uint16_t file_info_level;
		char *data = NULL;
		unsigned int data_size = 0;
		bool delete_pending = false;
		struct timespec write_time_ts;
		struct file_id fileid;
		struct ea_list *ea_list = NULL;
		int lock_data_count = 0;
		char *lock_data = NULL;
		size_t fixed_portion;

		ZERO_STRUCT(write_time_ts);

		switch (in_file_info_class) {
		case 0x0F:/* RAW_FILEINFO_SMB2_ALL_EAS */
			file_info_level = 0xFF00 | in_file_info_class;
			break;

		case 0x12:/* RAW_FILEINFO_SMB2_ALL_INFORMATION */
			file_info_level = 0xFF00 | in_file_info_class;
			break;

		default:
			/* the levels directly map to the passthru levels */
			file_info_level = in_file_info_class + 1000;
			break;
		}

		if (fsp->fake_file_handle) {
			/*
			 * This is actually for the QUOTA_FAKE_FILE --metze
			 */

			/* We know this name is ok, it's already passed the checks. */

		} else if (fsp->fh->fd == -1) {
			/*
			 * This is actually a QFILEINFO on a directory
			 * handle (returned from an NT SMB). NT5.0 seems
			 * to do this call. JRA.
			 */

			if (INFO_LEVEL_IS_UNIX(file_info_level)) {
				/* Always do lstat for UNIX calls. */
				if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) {
					DEBUG(3,("smbd_smb2_getinfo_send: "
						 "SMB_VFS_LSTAT of %s failed "
						 "(%s)\n", fsp_str_dbg(fsp),
						 strerror(errno)));
					status = map_nt_error_from_unix(errno);
					tevent_req_nterror(req, status);
					return tevent_req_post(req, ev);
				}
			} else if (SMB_VFS_STAT(conn, fsp->fsp_name)) {
				DEBUG(3,("smbd_smb2_getinfo_send: "
					 "SMB_VFS_STAT of %s failed (%s)\n",
					 fsp_str_dbg(fsp),
					 strerror(errno)));
				status = map_nt_error_from_unix(errno);
				tevent_req_nterror(req, status);
				return tevent_req_post(req, ev);
			}

			fileid = vfs_file_id_from_sbuf(conn,
						       &fsp->fsp_name->st);
			get_file_infos(fileid, fsp->name_hash,
				&delete_pending, &write_time_ts);
		} else {
			/*
			 * Original code - this is an open file.
			 */

			if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
				DEBUG(3, ("smbd_smb2_getinfo_send: "
					  "fstat of %s failed (%s)\n",
					  fsp_fnum_dbg(fsp), strerror(errno)));
				status = map_nt_error_from_unix(errno);
				tevent_req_nterror(req, status);
				return tevent_req_post(req, ev);
			}
			fileid = vfs_file_id_from_sbuf(conn,
						       &fsp->fsp_name->st);
			get_file_infos(fileid, fsp->name_hash,
				&delete_pending, &write_time_ts);
		}

		status = smbd_do_qfilepathinfo(conn, state,
					       file_info_level,
					       fsp,
					       fsp->fsp_name,
					       delete_pending,
					       write_time_ts,
					       ea_list,
					       lock_data_count,
					       lock_data,
					       STR_UNICODE,
					       in_output_buffer_length,
					       &fixed_portion,
					       &data,
					       &data_size);
		if (!NT_STATUS_IS_OK(status)) {
			SAFE_FREE(data);
			if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
				status = NT_STATUS_INVALID_INFO_CLASS;
			}
			tevent_req_nterror(req, status);
			return tevent_req_post(req, ev);
		}
		if (in_output_buffer_length < fixed_portion) {
			SAFE_FREE(data);
			tevent_req_nterror(
				req, NT_STATUS_INFO_LENGTH_MISMATCH);
			return tevent_req_post(req, ev);
		}
		if (data_size > 0) {
			state->out_output_buffer = data_blob_talloc(state,
								    data,
								    data_size);
			SAFE_FREE(data);
			if (tevent_req_nomem(state->out_output_buffer.data, req)) {
				return tevent_req_post(req, ev);
			}
			if (data_size > in_output_buffer_length) {
				state->out_output_buffer.length =
					in_output_buffer_length;
				status = STATUS_BUFFER_OVERFLOW;
			}
		}
		SAFE_FREE(data);
		break;
	}

	case SMB2_GETINFO_FS:
	{
		uint16_t file_info_level;
		char *data = NULL;
		int data_size = 0;
		size_t fixed_portion;

		/* the levels directly map to the passthru levels */
		file_info_level = in_file_info_class + 1000;

		status = smbd_do_qfsinfo(conn, state,
					 file_info_level,
					 STR_UNICODE,
					 in_output_buffer_length,
					 &fixed_portion,
					 fsp->fsp_name,
					 &data,
					 &data_size);
		/* some responses set STATUS_BUFFER_OVERFLOW and return
		   partial, but valid data */
		if (!(NT_STATUS_IS_OK(status) ||
		      NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW))) {
			SAFE_FREE(data);
			if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) {
				status = NT_STATUS_INVALID_INFO_CLASS;
			}
			tevent_req_nterror(req, status);
			return tevent_req_post(req, ev);
		}
		if (in_output_buffer_length < fixed_portion) {
			SAFE_FREE(data);
			tevent_req_nterror(
				req, NT_STATUS_INFO_LENGTH_MISMATCH);
			return tevent_req_post(req, ev);
		}
		if (data_size > 0) {
			state->out_output_buffer = data_blob_talloc(state,
								    data,
								    data_size);
			SAFE_FREE(data);
			if (tevent_req_nomem(state->out_output_buffer.data, req)) {
				return tevent_req_post(req, ev);
			}
			if (data_size > in_output_buffer_length) {
				state->out_output_buffer.length =
					in_output_buffer_length;
				status = STATUS_BUFFER_OVERFLOW;
			}
		}
		SAFE_FREE(data);
		break;
	}

	case SMB2_GETINFO_SECURITY:
	{
		uint8_t *p_marshalled_sd = NULL;
		size_t sd_size = 0;

		status = smbd_do_query_security_desc(conn,
				state,
				fsp,
				/* Security info wanted. */
				in_additional_information &
				SMB_SUPPORTED_SECINFO_FLAGS,
				in_output_buffer_length,
				&p_marshalled_sd,
				&sd_size);

		if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
			/* Return needed size. */
			state->out_output_buffer = data_blob_talloc(state,
								    NULL,
								    4);
			if (tevent_req_nomem(state->out_output_buffer.data, req)) {
				return tevent_req_post(req, ev);
			}
			SIVAL(state->out_output_buffer.data,0,(uint32_t)sd_size);
			state->status = NT_STATUS_BUFFER_TOO_SMALL;
			break;
		}
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(10,("smbd_smb2_getinfo_send: "
				 "smbd_do_query_security_desc of %s failed "
				 "(%s)\n", fsp_str_dbg(fsp),
				 nt_errstr(status)));
			tevent_req_nterror(req, status);
			return tevent_req_post(req, ev);
		}

		if (sd_size > 0) {
			state->out_output_buffer = data_blob_talloc(state,
								    p_marshalled_sd,
								    sd_size);
			if (tevent_req_nomem(state->out_output_buffer.data, req)) {
				return tevent_req_post(req, ev);
			}
		}
		break;
	}

	case SMB2_GETINFO_QUOTA:
		tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
		return tevent_req_post(req, ev);

	default:
		DEBUG(10,("smbd_smb2_getinfo_send: "
			"unknown in_info_type of %u "
			" for file %s\n",
			(unsigned int)in_info_type,
			fsp_str_dbg(fsp) ));

		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return tevent_req_post(req, ev);
	}

	state->status = status;
	tevent_req_done(req);
	return tevent_req_post(req, ev);
}
Example #23
0
static void smb1cli_trans_done(struct tevent_req *subreq)
{
	struct tevent_req *req =
		tevent_req_callback_data(subreq,
		struct tevent_req);
	struct smb1cli_trans_state *state =
		tevent_req_data(req,
		struct smb1cli_trans_state);
	NTSTATUS status;
	bool sent_all;
	struct iovec *recv_iov = NULL;
	uint8_t *inhdr;
	uint8_t wct;
	uint16_t *vwv;
	uint32_t vwv_ofs;
	uint32_t num_bytes;
	uint8_t *bytes;
	uint32_t bytes_ofs;
	uint8_t num_setup	= 0;
	uint16_t *setup		= NULL;
	uint32_t total_param	= 0;
	uint32_t num_param	= 0;
	uint32_t param_disp	= 0;
	uint32_t total_data	= 0;
	uint32_t num_data	= 0;
	uint32_t data_disp	= 0;
	uint8_t *param		= NULL;
	uint8_t *data		= NULL;

	status = smb1cli_req_recv(subreq, state,
				  &recv_iov,
				  &inhdr,
				  &wct,
				  &vwv,
				  &vwv_ofs,
				  &num_bytes,
				  &bytes,
				  &bytes_ofs,
				  NULL, /* pinbuf */
				  NULL, 0); /* expected */
	/*
	 * Do not TALLOC_FREE(subreq) here, we might receive more than
	 * one response for the same mid.
	 */

	/*
	 * We can receive something like STATUS_MORE_ENTRIES, so don't use
	 * !NT_STATUS_IS_OK(status) here.
	 */

	if (NT_STATUS_IS_ERR(status)) {
		goto fail;
	}

	if (recv_iov == NULL) {
		status = NT_STATUS_INVALID_NETWORK_RESPONSE;
		goto fail;
	}
	state->status = status;

	sent_all = ((state->param_sent == state->num_param)
		    && (state->data_sent == state->num_data));

	status = smb1cli_pull_trans(
		inhdr, wct, vwv, vwv_ofs,
		num_bytes, bytes, bytes_ofs,
		state->cmd, !sent_all, &num_setup, &setup,
		&total_param, &num_param, &param_disp, &param,
		&total_data, &num_data, &data_disp, &data);

	if (!NT_STATUS_IS_OK(status)) {
		goto fail;
	}

	if (!sent_all) {
		int iov_count;
		struct tevent_req *subreq2;

		smb1cli_trans_format(state, &wct, &iov_count);

		subreq2 = smb1cli_req_create(state, state->ev, state->conn,
					     state->cmd + 1,
					     state->additional_flags,
					     state->clear_flags,
					     state->additional_flags2,
					     state->clear_flags2,
					     state->timeout_msec,
					     state->pid, state->tid, state->uid,
					     wct, state->vwv,
					     iov_count, state->iov);
		if (tevent_req_nomem(subreq2, req)) {
			return;
		}
		smb1cli_req_set_mid(subreq2, state->mid);

		status = smb1cli_req_chain_submit(&subreq2, 1);

		if (!NT_STATUS_IS_OK(status)) {
			goto fail;
		}
		tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);

		return;
	}

	status = smb1cli_trans_pull_blob(
		state, &state->rparam, total_param, num_param, param,
		param_disp);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
		goto fail;
	}

	status = smb1cli_trans_pull_blob(
		state, &state->rdata, total_data, num_data, data,
		data_disp);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
		goto fail;
	}

	if ((state->rparam.total == state->rparam.received)
	    && (state->rdata.total == state->rdata.received)) {
		state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
		smb1cli_trans_cleanup_primary(state);
		tevent_req_done(req);
		return;
	}

	TALLOC_FREE(recv_iov);

	return;

 fail:
	smb1cli_trans_cleanup_primary(state);
	tevent_req_nterror(req, status);
}
Example #24
0
struct tevent_req *smb1cli_trans_send(
	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
	struct smbXcli_conn *conn, uint8_t cmd,
	uint8_t additional_flags, uint8_t clear_flags,
	uint16_t additional_flags2, uint16_t clear_flags2,
	uint32_t timeout_msec,
	uint32_t pid, uint16_t tid, uint16_t uid,
	const char *pipe_name, uint16_t fid, uint16_t function, int flags,
	uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
	uint8_t *param, uint32_t num_param, uint32_t max_param,
	uint8_t *data, uint32_t num_data, uint32_t max_data)
{
	struct tevent_req *req, *subreq;
	struct smb1cli_trans_state *state;
	int iov_count;
	uint8_t wct;
	NTSTATUS status;
	charset_t charset;

	req = tevent_req_create(mem_ctx, &state,
				struct smb1cli_trans_state);
	if (req == NULL) {
		return NULL;
	}

	if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
		if ((num_param > 0xffff) || (max_param > 0xffff)
		    || (num_data > 0xffff) || (max_data > 0xffff)) {
			DEBUG(3, ("Attempt to send invalid trans2 request "
				  "(setup %u, params %u/%u, data %u/%u)\n",
				  (unsigned)num_setup,
				  (unsigned)num_param, (unsigned)max_param,
				  (unsigned)num_data, (unsigned)max_data));
			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
			return tevent_req_post(req, ev);
		}
	}

	/*
	 * The largest wct will be for nttrans (19+num_setup). Make sure we
	 * don't overflow state->vwv in smb1cli_trans_format.
	 */

	if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
		return tevent_req_post(req, ev);
	}

	state->conn = conn;
	state->ev = ev;
	state->cmd = cmd;
	state->additional_flags = additional_flags;
	state->clear_flags = clear_flags;
	state->additional_flags2 = additional_flags2;
	state->clear_flags2 = clear_flags2;
	state->timeout_msec = timeout_msec;
	state->flags = flags;
	state->num_rsetup = 0;
	state->rsetup = NULL;
	state->pid = pid;
	state->tid = tid;
	state->uid = uid;
	ZERO_STRUCT(state->rparam);
	ZERO_STRUCT(state->rdata);

	if (smbXcli_conn_use_unicode(conn)) {
		charset = CH_UTF16LE;
	} else {
		charset = CH_DOS;
	}

	if ((pipe_name != NULL)
	    && (!convert_string_talloc(state, CH_UNIX, charset,
				       pipe_name, strlen(pipe_name) + 1,
				       &state->pipe_name_conv,
				       &state->pipe_name_conv_len))) {
		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
		return tevent_req_post(req, ev);
	}
	state->fid = fid;	/* trans2 */
	state->function = function; /* nttrans */

	state->setup = setup;
	state->num_setup = num_setup;
	state->max_setup = max_setup;

	state->param = param;
	state->num_param = num_param;
	state->param_sent = 0;
	state->rparam.max = max_param;

	state->data = data;
	state->num_data = num_data;
	state->data_sent = 0;
	state->rdata.max = max_data;

	smb1cli_trans_format(state, &wct, &iov_count);

	subreq = smb1cli_req_create(state, ev, conn, cmd,
				    state->additional_flags,
				    state->clear_flags,
				    state->additional_flags2,
				    state->clear_flags2,
				    state->timeout_msec,
				    state->pid, state->tid, state->uid,
				    wct, state->vwv,
				    iov_count, state->iov);
	if (tevent_req_nomem(subreq, req)) {
		return tevent_req_post(req, ev);
	}
	status = smb1cli_req_chain_submit(&subreq, 1);
	if (tevent_req_nterror(req, status)) {
		return tevent_req_post(req, state->ev);
	}
	tevent_req_set_callback(subreq, smb1cli_trans_done, req);

	/*
	 * Now get the MID of the primary request
	 * and mark it as persistent. This means
	 * we will able to send and receive multiple
	 * SMB pdus using this MID in both directions
	 * (including correct SMB signing).
	 */
	state->mid = smb1cli_req_mid(subreq);
	smb1cli_req_set_mid(subreq, state->mid);
	state->primary_subreq = subreq;
	talloc_set_destructor(state, smb1cli_trans_state_destructor);

	tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);

	return req;
}
Example #25
0
struct tevent_req *cli_trans_send(
	TALLOC_CTX *mem_ctx, struct event_context *ev,
	struct cli_state *cli, uint8_t cmd,
	const char *pipe_name, uint16_t fid, uint16_t function, int flags,
	uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
	uint8_t *param, uint32_t num_param, uint32_t max_param,
	uint8_t *data, uint32_t num_data, uint32_t max_data)
{
	struct tevent_req *req, *subreq;
	struct cli_trans_state *state;
	int iov_count;
	uint8_t wct;

	req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
	if (req == NULL) {
		return NULL;
	}

	if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
		if ((num_param > 0xffff) || (max_param > 0xffff)
		    || (num_data > 0xffff) || (max_data > 0xffff)) {
			DEBUG(3, ("Attempt to send invalid trans2 request "
				  "(setup %u, params %u/%u, data %u/%u)\n",
				  (unsigned)num_setup,
				  (unsigned)num_param, (unsigned)max_param,
				  (unsigned)num_data, (unsigned)max_data));
			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
			return tevent_req_post(req, ev);
		}
	}

	/*
	 * The largest wct will be for nttrans (19+num_setup). Make sure we
	 * don't overflow state->vwv in cli_trans_format.
	 */

	if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
		return tevent_req_post(req, ev);
	}

	state->cli = cli;
	state->ev = ev;
	state->cmd = cmd;
	state->flags = flags;
	state->num_rsetup = 0;
	state->rsetup = NULL;
	ZERO_STRUCT(state->rparam);
	ZERO_STRUCT(state->rdata);

	if ((pipe_name != NULL)
	    && (!convert_string_talloc(state, CH_UNIX,
				       cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
				       pipe_name, strlen(pipe_name) + 1,
				       &state->pipe_name_conv,
				       &state->pipe_name_conv_len, true))) {
		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
		return tevent_req_post(req, ev);
	}
	state->fid = fid;	/* trans2 */
	state->function = function; /* nttrans */

	state->setup = setup;
	state->num_setup = num_setup;
	state->max_setup = max_setup;

	state->param = param;
	state->num_param = num_param;
	state->param_sent = 0;
	state->rparam.max = max_param;

	state->data = data;
	state->num_data = num_data;
	state->data_sent = 0;
	state->rdata.max = max_data;

	cli_trans_format(state, &wct, &iov_count);

	subreq = cli_smb_req_create(state, ev, cli, cmd, 0, wct, state->vwv,
				    iov_count, state->iov);
	if (tevent_req_nomem(subreq, req)) {
		return tevent_req_post(req, ev);
	}
	state->mid = cli_smb_req_mid(subreq);
	if (!cli_smb_req_send(subreq)) {
		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
		return tevent_req_post(req, state->ev);
	}
	cli_state_seqnum_persistent(cli, state->mid);
	tevent_req_set_callback(subreq, cli_trans_done, req);
	return req;
}
Example #26
0
static void smb1cli_trans_done2(struct tevent_req *subreq2)
{
	struct tevent_req *req =
		tevent_req_callback_data(subreq2,
		struct tevent_req);
	struct smb1cli_trans_state *state =
		tevent_req_data(req,
		struct smb1cli_trans_state);
	NTSTATUS status;
	bool sent_all;
	uint32_t seqnum;

	/*
	 * First backup the seqnum of the secondary request
	 * and attach it to the primary request.
	 */
	seqnum = smb1cli_req_seqnum(subreq2);
	smb1cli_req_set_seqnum(state->primary_subreq, seqnum);

	/* This was a one way request */
	status = smb1cli_req_recv(subreq2, state,
				  NULL, /* recv_iov */
				  NULL, /* phdr */
				  NULL, /* pwct */
				  NULL, /* pvwv */
				  NULL, /* pvwv_offset */
				  NULL, /* pnum_bytes */
				  NULL, /* pbytes */
				  NULL, /* pbytes_offset */
				  NULL, /* pinbuf */
				  NULL, 0); /* expected */
	TALLOC_FREE(subreq2);

	if (!NT_STATUS_IS_OK(status)) {
		goto fail;
	}

	sent_all = ((state->param_sent == state->num_param)
		    && (state->data_sent == state->num_data));

	if (!sent_all) {
		uint8_t wct;
		int iov_count;

		smb1cli_trans_format(state, &wct, &iov_count);

		subreq2 = smb1cli_req_create(state, state->ev, state->conn,
					     state->cmd + 1,
					     state->additional_flags,
					     state->clear_flags,
					     state->additional_flags2,
					     state->clear_flags2,
					     state->timeout_msec,
					     state->pid, state->tid, state->uid,
					     wct, state->vwv,
					     iov_count, state->iov);
		if (tevent_req_nomem(subreq2, req)) {
			return;
		}
		smb1cli_req_set_mid(subreq2, state->mid);

		status = smb1cli_req_chain_submit(&subreq2, 1);

		if (!NT_STATUS_IS_OK(status)) {
			goto fail;
		}
		tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
		return;
	}

	return;

 fail:
	smb1cli_trans_cleanup_primary(state);
	tevent_req_nterror(req, status);
}
Example #27
0
static struct tevent_req *smbd_smb2_ioctl_send(TALLOC_CTX *mem_ctx,
					       struct tevent_context *ev,
					       struct smbd_smb2_request *smb2req,
					       struct files_struct *fsp,
					       uint32_t in_ctl_code,
					       DATA_BLOB in_input,
					       uint32_t in_max_output,
					       uint32_t in_flags)
{
	struct tevent_req *req;
	struct smbd_smb2_ioctl_state *state;
	struct smb_request *smbreq;

	req = tevent_req_create(mem_ctx, &state,
				struct smbd_smb2_ioctl_state);
	if (req == NULL) {
		return NULL;
	}
	state->smb2req = smb2req;
	state->smbreq = NULL;
	state->fsp = fsp;
	state->in_input = in_input;
	state->in_max_output = in_max_output;
	state->out_output = data_blob_null;

	DEBUG(10, ("smbd_smb2_ioctl: ctl_code[0x%08x] %s, %s\n",
		   (unsigned)in_ctl_code,
		   fsp ? fsp_str_dbg(fsp) : "<no handle>",
		   fsp_fnum_dbg(fsp)));

	smbreq = smbd_smb2_fake_smb_request(smb2req);
	if (tevent_req_nomem(smbreq, req)) {
		return tevent_req_post(req, ev);
	}
	state->smbreq = smbreq;

	switch (in_ctl_code & IOCTL_DEV_TYPE_MASK) {
	case FSCTL_DFS:
		return smb2_ioctl_dfs(in_ctl_code, ev, req, state);
		break;
	case FSCTL_FILESYSTEM:
		return smb2_ioctl_filesys(in_ctl_code, ev, req, state);
		break;
	case FSCTL_NAMED_PIPE:
		return smb2_ioctl_named_pipe(in_ctl_code, ev, req, state);
		break;
	case FSCTL_NETWORK_FILESYSTEM:
		return smb2_ioctl_network_fs(in_ctl_code, ev, req, state);
		break;
	default:
		if (IS_IPC(smbreq->conn)) {
			tevent_req_nterror(req, NT_STATUS_FS_DRIVER_REQUIRED);
		} else {
			tevent_req_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
		}

		return tevent_req_post(req, ev);
		break;
	}

	tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
	return tevent_req_post(req, ev);
}