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); }
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); }
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, ¶m->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); }