/* * Starts the creation of a new printer file, which will be deleted * automatically once it has been closed and printed. * * SetupLength is the number of bytes in the first part of the resulting * print spool file which contains printer-specific control strings. * * Mode can have the following values: * 0 Text mode. The server may optionally * expand tabs to a series of spaces. * 1 Graphics mode. No conversion of data * should be done by the server. * * IdentifierString can be used by the server to provide some sort of * per-client identifying component to the print file. * * When the file is closed, it will be sent to the spooler and printed. */ smb_sdrc_t smb_pre_open_print_file(smb_request_t *sr) { struct open_param *op = &sr->arg.open; char *path; char *identifier; uint32_t new_id; uint16_t setup; uint16_t mode; int rc; static uint32_t tmp_id = 10000; bzero(op, sizeof (sr->arg.open)); rc = smbsr_decode_vwv(sr, "ww", &setup, &mode); if (rc == 0) rc = smbsr_decode_data(sr, "%S", sr, &identifier); if (rc == 0) { path = smb_srm_zalloc(sr, MAXPATHLEN); op->fqi.fq_path.pn_path = path; new_id = atomic_inc_32_nv(&tmp_id); (void) snprintf(path, MAXPATHLEN, "%s%05u", identifier, new_id); } op->create_disposition = FILE_OVERWRITE_IF; op->create_options = FILE_NON_DIRECTORY_FILE; DTRACE_SMB_2(op__OpenPrintFile__start, smb_request_t *, sr, struct open_param *, op); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
/* * smb_com_query_information (aka getattr) */ smb_sdrc_t smb_pre_query_information(smb_request_t *sr) { int rc; smb_fqi_t *fqi = &sr->arg.dirop.fqi; rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path); DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr, smb_fqi_t *, fqi); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
/* * The create directory message is sent to create a new directory. The * appropriate Tid and additional pathname are passed. The directory must * not exist for it to be created. * * Client Request Description * ================================== ================================= * UCHAR WordCount; Count of parameter words = 0 * USHORT ByteCount; Count of data bytes; min = 2 * UCHAR BufferFormat; 0x04 * STRING DirectoryName[]; Directory name * * Servers require clients to have at least create permission for the * subtree containing the directory in order to create a new directory. * The creator's access rights to the new directory are be determined by * local policy on the server. * * Server Response Description * ================================== ================================= * UCHAR WordCount; Count of parameter words = 0 * USHORT ByteCount; Count of data bytes = 0 */ smb_sdrc_t smb_pre_create_directory(smb_request_t *sr) { int rc; rc = smbsr_decode_data(sr, "%S", sr, &sr->arg.dirop.fqi.fq_path.pn_path); DTRACE_SMB_2(op__CreateDirectory__start, smb_request_t *, sr, struct dirop *, &sr->arg.dirop); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
/* * smb_com_nt_create_andx * * This command is used to create or open a file or directory. * * Client Request Description * ================================= ================================== * * UCHAR WordCount; Count of parameter words = 24 * UCHAR AndXCommand; Secondary command; 0xFF = None * UCHAR AndXReserved; Reserved (must be 0) * USHORT AndXOffset; Offset to next command WordCount * UCHAR Reserved; Reserved (must be 0) * USHORT NameLength; Length of Name[] in bytes * ULONG Flags; Create bit set: * 0x02 - Request an oplock * 0x04 - Request a batch oplock * 0x08 - Target of open must be * directory * ULONG RootDirectoryFid; If non-zero, open is relative to * this directory * ACCESS_MASK DesiredAccess; access desired * LARGE_INTEGER AllocationSize; Initial allocation size * ULONG ExtFileAttributes; File attributes * ULONG ShareAccess; Type of share access * ULONG CreateDisposition; Action to take if file exists or * not * ULONG CreateOptions; Options to use if creating a file * ULONG ImpersonationLevel; Security QOS information * UCHAR SecurityFlags; Security tracking mode flags: * 0x1 - SECURITY_CONTEXT_TRACKING * 0x2 - SECURITY_EFFECTIVE_ONLY * USHORT ByteCount; Length of byte parameters * STRING Name[]; File to open or create * * The DesiredAccess parameter is specified in section 3.7 on Access Mask * Encoding. * * If no value is specified, it still allows an application to query * attributes without actually accessing the file. * * The ExtFIleAttributes parameter specifies the file attributes and flags * for the file. The parameter's value is the sum of allowed attributes and * flags defined in section 3.11 on Extended File Attribute Encoding * * The ShareAccess field Specifies how this file can be shared. This * parameter must be some combination of the following values: * * Name Value Meaning * 0 Prevents the file from being shared. * FILE_SHARE_READ 0x00000001 Other open operations can be performed on * the file for read access. * FILE_SHARE_WRITE 0x00000002 Other open operations can be performed on * the file for write access. * FILE_SHARE_DELETE 0x00000004 Other open operations can be performed on * the file for delete access. * * The CreateDisposition parameter can contain one of the following values: * * CREATE_NEW Creates a new file. The function fails if the * specified file already exists. * CREATE_ALWAYS Creates a new file. The function overwrites the file * if it exists. * OPEN_EXISTING Opens the file. The function fails if the file does * not exist. * OPEN_ALWAYS Opens the file, if it exists. If the file does not * exist, act like CREATE_NEW. * TRUNCATE_EXISTING Opens the file. Once opened, the file is truncated so * that its size is zero bytes. The calling process must * open the file with at least GENERIC_WRITE access. The * function fails if the file does not exist. * * The ImpersonationLevel parameter can contain one or more of the * following values: * * SECURITY_ANONYMOUS Specifies to impersonate the client at the * Anonymous impersonation level. * SECURITY_IDENTIFICATION Specifies to impersonate the client at the * Identification impersonation level. * SECURITY_IMPERSONATION Specifies to impersonate the client at the * Impersonation impersonation level. * SECURITY_DELEGATION Specifies to impersonate the client at the * Delegation impersonation level. * * The SecurityFlags parameter can have either of the following two flags * set: * * SECURITY_CONTEXT_TRACKING Specifies that the security tracking mode is * dynamic. If this flag is not specified, * Security Tracking Mode is static. * SECURITY_EFFECTIVE_ONLY Specifies that only the enabled aspects of * the client's security context are available * to the server. If you do not specify this * flag, all aspects of the client's security * context are available. This flag allows the * client to limit the groups and privileges * that a server can use while impersonating the * client. * * The response is as follows: * * Server Response Description * ================================= ================================== * * UCHAR WordCount; Count of parameter words = 26 * UCHAR AndXCommand; Secondary 0xFF = None * command; * UCHAR AndXReserved; MBZ * USHORT AndXOffset; Offset to next command WordCount * UCHAR OplockLevel; The oplock level granted * 0 - No oplock granted * 1 - Exclusive oplock granted * 2 - Batch oplock granted * 3 - Level II oplock granted * USHORT Fid; The file ID * ULONG CreateAction; The action taken * TIME CreationTime; The time the file was created * TIME LastAccessTime; The time the file was accessed * TIME LastWriteTime; The time the file was last written * TIME ChangeTime; The time the file was last changed * ULONG ExtFileAttributes; The file attributes * LARGE_INTEGER AllocationSize; The number of bytes allocated * LARGE_INTEGER EndOfFile; The end of file offset * USHORT FileType; * USHORT DeviceState; state of IPC device (e.g. pipe) * BOOLEAN Directory; TRUE if this is a directory * USHORT ByteCount; = 0 * * The following SMBs may follow SMB_COM_NT_CREATE_ANDX: * * SMB_COM_READ SMB_COM_READ_ANDX * SMB_COM_IOCTL */ smb_sdrc_t smb_pre_nt_create_andx(smb_request_t *sr) { struct open_param *op = &sr->arg.open; uint8_t SecurityFlags; uint32_t ImpersonationLevel; uint16_t NameLength; int rc; bzero(op, sizeof (sr->arg.open)); rc = smbsr_decode_vwv(sr, "5.wlllqlllllb", &NameLength, &op->nt_flags, &op->rootdirfid, &op->desired_access, &op->dsize, &op->dattr, &op->share_access, &op->create_disposition, &op->create_options, &ImpersonationLevel, &SecurityFlags); if (rc == 0) { if (NameLength == 0) { op->fqi.fq_path.pn_path = "\\"; } else if (NameLength >= MAXPATHLEN) { smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND, ERRDOS, ERROR_PATH_NOT_FOUND); rc = -1; } else { rc = smbsr_decode_data(sr, "%#u", sr, NameLength, &op->fqi.fq_path.pn_path); } } op->op_oplock_level = SMB_OPLOCK_NONE; if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPLOCK) { if (op->nt_flags & NT_CREATE_FLAG_REQUEST_OPBATCH) op->op_oplock_level = SMB_OPLOCK_BATCH; else op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; } DTRACE_SMB_2(op__NtCreateX__start, smb_request_t *, sr, struct open_param *, op); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
smb_sdrc_t smb_com_write_print_file(smb_request_t *sr) { smb_rw_param_t *param = sr->arg.rw; smb_node_t *node; smb_attr_t attr; int rc; if (sr->sr_server->sv_cfg.skc_print_enable == 0 || !STYPE_ISPRN(sr->tid_tree->t_res_type)) { smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, ERRDOS, ERROR_BAD_DEV_TYPE); return (SDRC_ERROR); } smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); } node = sr->fid_ofile->f_node; sr->user_cr = smb_ofile_getcred(sr->fid_ofile); if (smb_node_getattr(sr, node, &attr) != 0) { smbsr_error(sr, NT_STATUS_INTERNAL_ERROR, ERRDOS, ERROR_INTERNAL_ERROR); return (SDRC_ERROR); } if ((smbsr_decode_data(sr, "D", ¶m->rw_vdb)) != 0) { smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, ERRDOS, ERROR_INVALID_PARAMETER); return (SDRC_ERROR); } param->rw_count = param->rw_vdb.vdb_len; param->rw_offset = attr.sa_vattr.va_size; param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; if ((rc = smb_common_write(sr, param)) != 0) { if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) smbsr_errno(sr, rc); return (SDRC_ERROR); } rc = smbsr_encode_empty_result(sr); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
smb_sdrc_t smb_pre_open(smb_request_t *sr) { struct open_param *op = &sr->arg.open; int rc; bzero(op, sizeof (sr->arg.open)); rc = smbsr_decode_vwv(sr, "ww", &op->omode, &op->fqi.fq_sattr); if (rc == 0) rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.fq_path.pn_path); DTRACE_SMB_2(op__Open__start, smb_request_t *, sr, struct open_param *, op); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
/* * Create a new file and return a fid. The file is specified using * a fully qualified name relative to the tree. */ smb_sdrc_t smb_pre_create_new(smb_request_t *sr) { struct open_param *op = &sr->arg.open; int rc; bzero(op, sizeof (sr->arg.open)); rc = smbsr_decode_vwv(sr, "wl", &op->dattr, &op->mtime.tv_sec); if (rc == 0) rc = smbsr_decode_data(sr, "%S", sr, &op->fqi.fq_path.pn_path); op->create_disposition = FILE_CREATE; DTRACE_SMB_2(op__CreateNew__start, smb_request_t *, sr, struct open_param *, op); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
smb_sdrc_t smb_pre_negotiate(smb_request_t *sr) { smb_kmod_cfg_t *skc; smb_arg_negotiate_t *negprot; int dialect; int pos; int rc = 0; skc = &sr->session->s_cfg; negprot = smb_srm_zalloc(sr, sizeof (smb_arg_negotiate_t)); negprot->ni_index = -1; sr->sr_negprot = negprot; for (pos = 0; smbsr_decode_data_avail(sr); pos++) { if (smbsr_decode_data(sr, "%L", sr, &negprot->ni_name) != 0) { smbsr_error(sr, 0, ERRSRV, ERRerror); rc = -1; break; } if ((dialect = smb_xlate_dialect(negprot->ni_name)) < 0) continue; /* * Conditionally recognize the SMB2 dialects. */ if (dialect >= DIALECT_SMB2002 && skc->skc_max_protocol < SMB_VERS_2_BASE) continue; if (negprot->ni_dialect < dialect) { negprot->ni_dialect = dialect; negprot->ni_index = pos; } } DTRACE_SMB_2(op__Negotiate__start, smb_request_t *, sr, smb_arg_negotiate_t, negprot); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
/* * smb_pre_open_andx * For compatibility with windows servers, the search attributes * specified in the request are ignored. */ smb_sdrc_t smb_pre_open_andx(smb_request_t *sr) { struct open_param *op = &sr->arg.open; uint16_t flags; uint32_t creation_time; uint16_t file_attr, sattr; int rc; bzero(op, sizeof (sr->arg.open)); rc = smbsr_decode_vwv(sr, "b.wwwwwlwll4.", &sr->andx_com, &sr->andx_off, &flags, &op->omode, &sattr, &file_attr, &creation_time, &op->ofun, &op->dsize, &op->timeo); if (rc == 0) { rc = smbsr_decode_data(sr, "%u", sr, &op->fqi.fq_path.pn_path); op->dattr = file_attr; if (flags & 2) op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE; else if (flags & 4) op->op_oplock_level = SMB_OPLOCK_BATCH; else op->op_oplock_level = SMB_OPLOCK_NONE; if ((creation_time != 0) && (creation_time != UINT_MAX)) op->crtime.tv_sec = smb_time_local_to_gmt(sr, creation_time); op->crtime.tv_nsec = 0; op->create_disposition = smb_ofun_to_crdisposition(op->ofun); } DTRACE_SMB_2(op__OpenX__start, smb_request_t *, sr, struct open_param *, op); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
smb_sdrc_t smb_com_session_setup_andx(smb_request_t *sr) { smb_sessionsetup_info_t sinfo; smb_session_key_t *session_key = NULL; char ipaddr_buf[INET6_ADDRSTRLEN]; int native_lm; int auth_res; int rc; bzero(&sinfo, sizeof (smb_sessionsetup_info_t)); if (sr->session->dialect >= NT_LM_0_12) { rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com, &sr->andx_off, &sinfo.ssi_maxbufsize, &sinfo.ssi_maxmpxcount, &sinfo.ssi_vcnumber, &sinfo.ssi_sesskey, &sinfo.ssi_cipwlen, &sinfo.ssi_cspwlen, &sinfo.ssi_capabilities); if (rc != 0) return (SDRC_ERROR); sinfo.ssi_cipwd = kmem_alloc(sinfo.ssi_cipwlen + 1, KM_SLEEP); sinfo.ssi_cspwd = kmem_alloc(sinfo.ssi_cspwlen + 1, KM_SLEEP); /* * The padding between the Native OS and Native LM is a * bit strange. On NT4.0, there is a 2 byte pad between * the OS (Windows NT 1381) and LM (Windows NT 4.0). * On Windows 2000, there is no padding between the OS * (Windows 2000 2195) and LM (Windows 2000 5.0). * * If the padding is removed from this decode string * the NT4.0 LM comes out as an empty string. * * So if the client's native OS is Win NT we consider * the padding otherwise we don't. */ rc = smbsr_decode_data(sr, "%#c#cuuu", sr, sinfo.ssi_cipwlen, sinfo.ssi_cipwd, sinfo.ssi_cspwlen, sinfo.ssi_cspwd, &sinfo.ssi_user, &sinfo.ssi_domain, &sinfo.ssi_native_os); if (rc != 0) { kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1); kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1); return (SDRC_ERROR); } sinfo.ssi_cipwd[sinfo.ssi_cipwlen] = 0; sinfo.ssi_cspwd[sinfo.ssi_cspwlen] = 0; sr->session->native_os = smbnative_os_value(sinfo.ssi_native_os); if (sr->session->native_os == NATIVE_OS_WINNT) rc = smbsr_decode_data(sr, "%,u", sr, &sinfo.ssi_native_lm); else rc = smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_native_lm); /* * If the Native Lanman cannot be determined, * default to Windows NT. */ if (rc != 0 || sinfo.ssi_native_lm == NULL) sinfo.ssi_native_lm = "NT LAN Manager 4.0"; } else { rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com, &sr->andx_off, &sinfo.ssi_maxbufsize, &sinfo.ssi_maxmpxcount, &sinfo.ssi_vcnumber, &sinfo.ssi_sesskey, &sinfo.ssi_cipwlen); if (rc != 0) return (SDRC_ERROR); sinfo.ssi_cipwd = kmem_alloc(sinfo.ssi_cipwlen + 1, KM_SLEEP); rc = smbsr_decode_data(sr, "%#c", sr, sinfo.ssi_cipwlen, sinfo.ssi_cipwd); if (rc != 0) { kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1); return (SDRC_ERROR); } sinfo.ssi_cipwd[sinfo.ssi_cipwlen] = 0; /* * Despite the CIFS/1.0 spec, the rest of this message is * not always present. We need to try to get the account * name and the primary domain but we don't care about the * the native OS or native LanMan fields. */ if (smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_user) != 0) sinfo.ssi_user = ""; if (smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_domain) != 0) sinfo.ssi_domain = ""; sr->session->native_os = NATIVE_OS_WINNT; sinfo.ssi_native_lm = "NT LAN Manager 4.0"; } /* * If the sinfo.ssi_vcnumber is zero, we can discard any * other connections associated with this client. */ sr->session->vcnumber = sinfo.ssi_vcnumber; if (sinfo.ssi_vcnumber == 0) smb_server_reconnection_check(sr->sr_server, sr->session); auth_res = smb_authenticate(sr, &sinfo, &session_key); if (sinfo.ssi_cipwd) kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1); if (auth_res == SMB_AUTH_FAILED) { if (sinfo.ssi_cspwd) kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1); return (SDRC_ERROR); } native_lm = smbnative_lm_value(sinfo.ssi_native_lm); if (native_lm == NATIVE_LM_WIN2000) sinfo.ssi_capabilities |= CAP_LARGE_FILES | CAP_LARGE_READX | CAP_LARGE_WRITEX; sr->session->smb_msg_size = sinfo.ssi_maxbufsize; sr->session->capabilities = sinfo.ssi_capabilities; /* * Check to see if SMB signing is enable, but if it is already turned * on leave it. * The first authenticated logon provides the MAC key and sequence * numbers for signing all further session on the * same network connection. */ if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) && (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) && session_key) smb_sign_init(sr, session_key, (char *)sinfo.ssi_cspwd, sinfo.ssi_cspwlen); if (sinfo.ssi_cspwd) kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1); if (session_key) kmem_free(session_key, sizeof (smb_session_key_t)); if (!(sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) && (sr->sr_cfg->skc_signing_required)) { (void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf, SMB_IPSTRLEN(sr->session->ipaddr.a_family)); cmn_err(CE_NOTE, "SmbSessonSetupX: client %s is not capable of signing", ipaddr_buf); smbsr_error(sr, NT_STATUS_LOGON_FAILURE, ERRDOS, ERROR_LOGON_FAILURE); return (SDRC_ERROR); } /* * NT systems use different native OS and native LanMan values * dependent on whether they are acting as a client or a server. * As a server, NT 4.0 responds with the following values: * * NativeOS: Windows NT 4.0 * NativeLM: NT LAN Manager 4.0 * * We should probably use the same values as NT but this code has * been using the product name and "Windows NT 4.0" for a long time * and I don't know if a change would cause any problems (see the * conditional test below). */ rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%uuu", 3, sr->andx_com, -1, /* andx_off */ (auth_res == SMB_AUTH_GUEST) ? 1 : 0, VAR_BCC, sr, "Windows NT 4.0", "NT LAN Manager 4.0", sr->sr_cfg->skc_nbdomain); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); }
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); }