Example #1
0
smb_sdrc_t
smb_com_echo(struct smb_request *sr)
{
	unsigned short necho;
	unsigned short nbytes;
	unsigned short i;
	struct mbuf_chain reply;
	char *data;

	if (smbsr_decode_vwv(sr, "w", &necho) != 0)
		return (SDRC_ERROR);

	nbytes = sr->smb_bcc;
	data = smb_srm_zalloc(sr, nbytes);

	if (smb_mbc_decodef(&sr->smb_data, "#c", nbytes, data))
		return (SDRC_ERROR);

	for (i = 1; i <= necho; ++i) {
		MBC_INIT(&reply, SMB_HEADER_ED_LEN + 10 + nbytes);

		(void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT,
		    sr->first_smb_com,
		    sr->smb_rcls,
		    sr->smb_reh,
		    sr->smb_err,
		    sr->smb_flg | SMB_FLAGS_REPLY,
		    sr->smb_flg2,
		    sr->smb_pid_high,
		    sr->smb_sig,
		    sr->smb_tid,
		    sr->smb_pid,
		    sr->smb_uid,
		    sr->smb_mid);

		(void) smb_mbc_encodef(&reply, "bww#c", 1, i,
		    nbytes, nbytes, data);

		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
			smb_sign_reply(sr, &reply);

		(void) smb_session_send(sr->session, 0, &reply);
	}

	return (SDRC_NO_REPLY);
}
Example #2
0
smb_sdrc_t
smb_com_echo(struct smb_request *sr)
{
	unsigned short necho;
	unsigned short nbytes;
	unsigned short i;
	struct mbuf_chain reply;
	char *data;
	uint16_t	pid_hi, pid_lo;

	pid_hi = sr->smb_pid >> 16;
	pid_lo = (uint16_t)sr->smb_pid;

	if (smbsr_decode_vwv(sr, "w", &necho) != 0)
		return (SDRC_ERROR);

	/*
	 * Don't let the client fool us into doing
	 * more work than is "reasonable".
	 */
	if (necho > smb_max_echo)
		necho = smb_max_echo;

	nbytes = sr->smb_bcc;
	data = smb_srm_zalloc(sr, nbytes);

	if (smb_mbc_decodef(&sr->smb_data, "#c", nbytes, data))
		return (SDRC_ERROR);

	for (i = 1; i <= necho; ++i) {

		/*
		 * According to [MS-CIFS] 3.3.5.32 echo is
		 * subject to cancellation.
		 */
		if (sr->sr_state != SMB_REQ_STATE_ACTIVE)
			break;

		MBC_INIT(&reply, SMB_HEADER_ED_LEN + 10 + nbytes);

		(void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT,
		    sr->first_smb_com,
		    sr->smb_rcls,
		    sr->smb_reh,
		    sr->smb_err,
		    sr->smb_flg | SMB_FLAGS_REPLY,
		    sr->smb_flg2,
		    pid_hi,
		    sr->smb_sig,
		    sr->smb_tid,
		    pid_lo,
		    sr->smb_uid,
		    sr->smb_mid);

		(void) smb_mbc_encodef(&reply, "bww#c", 1, i,
		    nbytes, nbytes, data);

		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
			smb_sign_reply(sr, &reply);

		(void) smb_session_send(sr->session, 0, &reply);

		delay(MSEC_TO_TICK(100));
	}

	return (SDRC_NO_REPLY);
}
void
smb_reply_notify_change_request(smb_request_t *sr)
{
	smb_node_t	*node;
	smb_srqueue_t	*srq;
	int		total_bytes, n_setup, n_param, n_data;
	int		param_off, param_pad, data_off, data_pad;
	struct		smb_xa *xa;
	smb_error_t	err;

	SMB_REQ_VALID(sr);
	srq = sr->session->s_srqueue;
	smb_srqueue_waitq_to_runq(srq);

	xa = sr->r_xa;
	node = sr->sr_ncr.nc_node;

	if (--node->waiting_event == 0) {
		node->flags &= ~(NODE_FLAGS_NOTIFY_CHANGE | NODE_FLAGS_CHANGED);
		smb_fem_fcn_uninstall(node);
	}

	mutex_enter(&sr->sr_mutex);
	switch (sr->sr_state) {

	case SMB_REQ_STATE_EVENT_OCCURRED:
		sr->sr_state = SMB_REQ_STATE_ACTIVE;

		/* many things changed */

		(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0L);

		/* setup the NT transact reply */

		n_setup = MBC_LENGTH(&xa->rep_setup_mb);
		n_param = MBC_LENGTH(&xa->rep_param_mb);
		n_data  = MBC_LENGTH(&xa->rep_data_mb);

		n_setup = (n_setup + 1) / 2; /* Convert to setup words */
		param_pad = 1; /* must be one */
		param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
		/* Pad to 4 bytes */
		data_pad = (4 - ((param_off + n_param) & 3)) % 4;
		/* Param off from hdr */
		data_off = param_off + n_param + data_pad;
		total_bytes = param_pad + n_param + data_pad + n_data;

		(void) smbsr_encode_result(sr, 18+n_setup, total_bytes,
		    "b3.llllllllbCw#.C#.C",
		    18 + n_setup,	/* wct */
		    n_param,		/* Total Parameter Bytes */
		    n_data,		/* Total Data Bytes */
		    n_param,		/* Total Parameter Bytes this buffer */
		    param_off,		/* Param offset from header start */
		    0,			/* Param displacement */
		    n_data,		/* Total Data Bytes this buffer */
		    data_off,		/* Data offset from header start */
		    0,			/* Data displacement */
		    n_setup,		/* suwcnt */
		    &xa->rep_setup_mb,	/* setup[] */
		    total_bytes,	/* Total data bytes */
		    param_pad,
		    &xa->rep_param_mb,
		    data_pad,
		    &xa->rep_data_mb);
		break;

	case SMB_REQ_STATE_CANCELED:
		err.status   = NT_STATUS_CANCELLED;
		err.errcls   = ERRDOS;
		err.errcode  = ERROR_OPERATION_ABORTED;
		smbsr_set_error(sr, &err);

		(void) smb_mbc_encodef(&sr->reply, "bwbw",
		    (short)0, 0L, (short)0, 0L);
		sr->smb_wct = 0;
		sr->smb_bcc = 0;
		break;
	default:
		ASSERT(0);
	}
	mutex_exit(&sr->sr_mutex);

	/* Setup the header */
	(void) smb_mbc_poke(&sr->reply, 0, SMB_HEADER_ED_FMT,
	    sr->first_smb_com,
	    sr->smb_rcls,
	    sr->smb_reh,
	    sr->smb_err,
	    sr->smb_flg | SMB_FLAGS_REPLY,
	    sr->smb_flg2,
	    sr->smb_pid_high,
	    sr->smb_sig,
	    sr->smb_tid,
	    sr->smb_pid,
	    sr->smb_uid,
	    sr->smb_mid);

	if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
		smb_sign_reply(sr, NULL);

	/* send the reply */
	DTRACE_PROBE1(ncr__reply, struct smb_request *, sr)
	(void) smb_session_send(sr->session, 0, &sr->reply);
	smbsr_cleanup(sr);

	mutex_enter(&sr->sr_mutex);
	sr->sr_state = SMB_REQ_STATE_COMPLETED;
	mutex_exit(&sr->sr_mutex);
	smb_srqueue_runq_exit(srq);
	smb_request_free(sr);
}
Example #4
0
smb_sdrc_t
smb_com_write_raw(struct smb_request *sr)
{
	smb_rw_param_t		*param = sr->arg.rw;
	int			rc = 0;
	int			session_send_rc = 0;
	uint16_t		addl_xfer_count;
	offset_t		addl_xfer_offset;
	struct mbuf_chain	reply;
	smb_error_t		err;

	if (sr->session->s_state != SMB_SESSION_STATE_WRITE_RAW_ACTIVE)
		return (SDRC_DROP_VC);

	if (!smb_raw_mode) {
		smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
		    ERROR_NOT_SUPPORTED);
		return (SDRC_ERROR);
	}

	smbsr_lookup_file(sr);
	if (sr->fid_ofile == NULL) {
		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
		return (SDRC_ERROR);
	}

	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);

	/*
	 * Send response if there is additional data to transfer.
	 * This will prompt the client to send the remaining data.
	 */
	addl_xfer_count = param->rw_total - param->rw_count;
	addl_xfer_offset = param->rw_count;

	if (addl_xfer_count != 0) {
		MBC_INIT(&reply, MLEN);
		(void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT "bww",
		    sr->first_smb_com,
		    sr->smb_rcls,
		    sr->smb_reh,
		    sr->smb_err,
		    sr->smb_flg | SMB_FLAGS_REPLY,
		    sr->smb_flg2,
		    sr->smb_pid_high,
		    sr->smb_sig,
		    sr->smb_tid,
		    sr->smb_pid,
		    sr->smb_uid,
		    sr->smb_mid, 1, -1, 0);

		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
			smb_sign_reply(sr, &reply);

		session_send_rc = smb_session_send(sr->session, 0, &reply);

		/*
		 * If the response failed, force write-through and
		 * complete the write before dealing with the error.
		 */
		if (session_send_rc != 0)
			param->rw_mode = SMB_WRMODE_WRITE_THRU;
	}

	/*
	 * While the response is in flight (and the data begins to arrive)
	 * write out the first data segment.
	 */
	if (smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
	    &param->rw_vdb) != 0)
		return (SDRC_ERROR);

	if (param->rw_count > 0)
		rc = smb_common_write(sr, param);

	if (session_send_rc != 0) {
		sr->smb_rcls = ERRSRV;
		sr->smb_err  = ERRusestd;
		goto write_raw_transfer_failed;
	}

	/*
	 * If we have more data to read then go get it
	 */
	if (addl_xfer_count > 0) {
		/*
		 * This is the only place where a worker thread should
		 * directly read from the session socket.  If the data
		 * is read successfully then the buffer (sr->sr_raw_data_buf)
		 * will need to be freed after the data is written.
		 */
		param->rw_offset += addl_xfer_offset;
		param->rw_vdb.vdb_uio.uio_loffset = param->rw_offset;
		param->rw_vdb.vdb_iovec[0].iov_len = addl_xfer_count;
		param->rw_vdb.vdb_uio.uio_resid = addl_xfer_count;
		if (smb_transfer_write_raw_data(sr, param) != 0)
			goto write_raw_transfer_failed;
	}

	/*
	 * Wake up session daemon since we now have all of our data and
	 * it's safe for the session daemon to resume processing SMB's.
	 */
	sr->session->s_write_raw_status = 0;
	sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;

	/*
	 * If we didn't write all the data from the first segment then
	 * there's not much point in continuing (we still wanted to
	 * read any additional data above since we don't necessarily
	 * want to drop the connection and we need to read through
	 * to the next SMB).
	 */
	if (rc != 0)
		goto notify_write_raw_complete;

	/*
	 * Write any additional data
	 */
	if (addl_xfer_count > 0) {
		rc = smb_common_write(sr, param);
		addl_xfer_offset += param->rw_count;
	}

	/*
	 * If we were called in "Write-behind" mode and the transfer was
	 * successful then we don't need to send any further response.
	 * If we were called in "Write-Through" mode or if the transfer
	 * failed we need to send a completion notification.  The "count"
	 * value will indicate whether the transfer was successful.
	 */
	if ((rc != 0) || SMB_WRMODE_IS_STABLE(param->rw_mode))
		goto notify_write_raw_complete;

	(void) smb_session_send(sr->session, SESSION_KEEP_ALIVE, NULL);
	return (SDRC_NO_REPLY);

write_raw_transfer_failed:
	/*
	 * Raw data transfer failed, wake up session daemon
	 */
	sr->session->s_write_raw_status = 20;
	sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;

notify_write_raw_complete:
	/*
	 * If we had an error fill in the appropriate error code
	 */
	if (rc != 0) {
		smbsr_map_errno(rc, &err);
		smbsr_set_error(sr, &err);
	}

	sr->first_smb_com = SMB_COM_WRITE_COMPLETE;
	rc = smbsr_encode_result(sr, 1, 0, "bww", 1, addl_xfer_offset, 0);
	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}