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); }
/* * smb_com_trans2_find_first2 * * Client Request Value * ============================ ================================== * * UCHAR WordCount 15 * UCHAR TotalDataCount Total size of extended attribute list * UCHAR SetupCount 1 * UCHAR Setup[0] TRANS2_FIND_FIRST2 * * Parameter Block Encoding Description * ============================ ================================== * USHORT SearchAttributes; * USHORT SearchCount; Maximum number of entries to return * USHORT Flags; Additional information: * Bit 0 - close search after this request * Bit 1 - close search if end of search * reached * Bit 2 - return resume keys for each * entry found * Bit 3 - continue search from previous * ending place * Bit 4 - find with backup intent * USHORT InformationLevel; See below * ULONG SearchStorageType; * STRING FileName; Pattern for the search * UCHAR Data[ TotalDataCount ] FEAList if InformationLevel is * QUERY_EAS_FROM_LIST * * Response Parameter Block Description * ============================ ================================== * * USHORT Sid; Search handle * USHORT SearchCount; Number of entries returned * USHORT EndOfSearch; Was last entry returned? * USHORT EaErrorOffset; Offset into EA list if EA error * USHORT LastNameOffset; Offset into data to file name of last * entry, if server needs it to resume * search; else 0 * UCHAR Data[ TotalDataCount ] Level dependent info about the matches * found in the search */ smb_sdrc_t smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) { int count; uint16_t sattr, odid; char *path; smb_odir_t *od; smb_find_args_t args; boolean_t eos; uint32_t odir_flags = 0; bzero(&args, sizeof (smb_find_args_t)); if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERROR_ACCESS_DENIED); return (SDRC_ERROR); } if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr, &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev, &path) != 0) { return (SDRC_ERROR); } if (smb_is_stream_name(path)) { smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, ERRDOS, ERROR_INVALID_NAME); return (SDRC_ERROR); } if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) { sr->user_cr = smb_user_getprivcred(sr->uid_user); odir_flags = SMB_ODIR_OPENF_BACKUP_INTENT; } args.fa_maxdata = smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); if (args.fa_maxdata == 0) return (SDRC_ERROR); if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) (void) smb_convert_wildcards(path); odid = smb_odir_open(sr, path, sattr, odir_flags); if (odid == 0) return (SDRC_ERROR); od = smb_tree_lookup_odir(sr->tid_tree, odid); if (od == NULL) return (SDRC_ERROR); count = smb_trans2_find_entries(sr, xa, od, &args, &eos); if (count == -1) { smb_odir_close(od); smb_odir_release(od); return (SDRC_ERROR); } if (count == 0) { smb_odir_close(od); smb_odir_release(od); smbsr_errno(sr, ENOENT); return (SDRC_ERROR); } if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { smb_odir_close(od); } /* else leave odir open for trans2_find_next2 */ smb_odir_release(od); (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww", odid, count, (eos) ? 1 : 0, 0, 0); return (SDRC_SUCCESS); }
/* * smb_odir_create * Allocate and populate an odir obect and add it to the tree's list. */ static uint16_t smb_odir_create(smb_request_t *sr, smb_node_t *dnode, char *pattern, uint16_t sattr, cred_t *cr) { smb_odir_t *od; smb_tree_t *tree; uint16_t odid; ASSERT(sr); ASSERT(sr->sr_magic == SMB_REQ_MAGIC); ASSERT(sr->tid_tree); ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC); ASSERT(dnode); ASSERT(dnode->n_magic == SMB_NODE_MAGIC); tree = sr->tid_tree; if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) { smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES, ERRDOS, ERROR_TOO_MANY_OPEN_FILES); return (0); } od = kmem_cache_alloc(smb_cache_odir, KM_SLEEP); bzero(od, sizeof (smb_odir_t)); mutex_init(&od->d_mutex, NULL, MUTEX_DEFAULT, NULL); od->d_refcnt = 0; od->d_state = SMB_ODIR_STATE_OPEN; od->d_magic = SMB_ODIR_MAGIC; od->d_opened_by_pid = sr->smb_pid; od->d_session = tree->t_session; od->d_cred = cr; /* * grab a ref for od->d_user * released in smb_odir_delete() */ smb_user_hold_internal(sr->uid_user); od->d_user = sr->uid_user; od->d_tree = tree; od->d_dnode = dnode; smb_node_ref(dnode); od->d_odid = odid; od->d_sattr = sattr; (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern)); od->d_flags = 0; if (smb_contains_wildcards(od->d_pattern)) od->d_flags |= SMB_ODIR_FLAG_WILDCARDS; if (vfs_has_feature(dnode->vp->v_vfsp, VFSFT_DIRENTFLAGS)) od->d_flags |= SMB_ODIR_FLAG_EDIRENT; if (smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE)) od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE; if (smb_tree_has_feature(tree, SMB_TREE_SHORTNAMES)) od->d_flags |= SMB_ODIR_FLAG_SHORTNAMES; if (SMB_TREE_SUPPORTS_CATIA(sr)) od->d_flags |= SMB_ODIR_FLAG_CATIA; if (SMB_TREE_SUPPORTS_ABE(sr)) od->d_flags |= SMB_ODIR_FLAG_ABE; if (dnode->flags & NODE_XATTR_DIR) od->d_flags |= SMB_ODIR_FLAG_XATTR; od->d_eof = B_FALSE; smb_llist_enter(&tree->t_odir_list, RW_WRITER); smb_llist_insert_tail(&tree->t_odir_list, od); smb_llist_exit(&tree->t_odir_list); atomic_inc_32(&tree->t_session->s_dir_cnt); return (odid); }