示例#1
0
/*
 * Build an SMB2 error response.  [MS-SMB2] 2.2.2
 */
void
smb2sr_put_error_data(smb_request_t *sr, uint32_t status, mbuf_chain_t *mbc)
{
	DWORD len;

	/*
	 * The common dispatch code writes this when it
	 * updates the SMB2 header before sending.
	 */
	sr->smb2_status = status;

	/* Rewind to the end of the SMB header. */
	sr->reply.chain_offset = sr->smb2_reply_hdr + SMB2_HDR_SIZE;

	/*
	 * NB: Must provide at least one byte of error data,
	 * per [MS-SMB2] 2.2.2
	 */
	if (mbc != NULL && (len = MBC_LENGTH(mbc)) != 0) {
		(void) smb_mbc_encodef(
		    &sr->reply,
		    "wwlC",
		    9,	/* StructSize */	/* w */
		    0,	/* reserved */		/* w */
		    len,			/* l */
		    mbc);			/* C */
	} else {
		(void) smb_mbc_encodef(
		    &sr->reply,
		    "wwl.",
		    9,	/* StructSize */	/* w */
		    0,	/* reserved */		/* w */
		    0);				/* l. */
	}
}
示例#2
0
/*
 * FileFsVolumeInformation
 */
uint32_t
smb2_qfs_volume(smb_request_t *sr)
{
	smb_tree_t *tree = sr->tid_tree;
	smb_node_t *snode;
	fsid_t fsid;
	uint32_t LabelLength;

	if (!STYPE_ISDSK(tree->t_res_type))
		return (NT_STATUS_INVALID_PARAMETER);

	snode = tree->t_snode;
	fsid = SMB_NODE_FSID(snode);

	LabelLength = smb_wcequiv_strlen(tree->t_volume);

	/*
	 * NT has the "supports objects" flag set to 1.
	 */
	(void) smb_mbc_encodef(
	    &sr->raw_data, "qllb.U",
	    0LL,	/* Volume creation time (q) */
	    fsid.val[0],	/* serial no.   (l) */
	    LabelLength,		/*	(l) */
	    0,		/* Supports objects	(b) */
	    /* reserved				(.) */
	    tree->t_volume);		/*	(U) */

	return (0);
}
/*
 * FilePipeInformation
 */
static uint32_t
smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi)
{
	_NOTE(ARGUNUSED(qi))
	smb_ofile_t *of = sr->fid_ofile;
	uint32_t	pipe_mode;
	uint32_t	nonblock;

	switch (of->f_ftype) {
	case SMB_FTYPE_BYTE_PIPE:
		pipe_mode = 0;	/* FILE_PIPE_BYTE_STREAM_MODE */
		break;
	case SMB_FTYPE_MESG_PIPE:
		pipe_mode = 1;	/* FILE_PIPE_MESSAGE_MODE */
		break;
	case SMB_FTYPE_DISK:
	case SMB_FTYPE_PRINTER:
	default:
		return (NT_STATUS_INVALID_PARAMETER);
	}
	nonblock = 0;	/* XXX todo: Get this from the pipe handle. */

	(void) smb_mbc_encodef(
	    &sr->raw_data, "ll",
	    pipe_mode, nonblock);

	return (0);
}
示例#4
0
/*
 * FileFsControlInformation
 */
uint32_t
smb2_qfs_control(smb_request_t *sr)
{
	smb_tree_t *tree = sr->tid_tree;

	if (!STYPE_ISDSK(tree->t_res_type))
		return (NT_STATUS_INVALID_PARAMETER);
	if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_QUOTA)) {
		/*
		 * Strange error per. [MS-FSCC 2.5.2]
		 * which means quotas not supported.
		 */
		return (NT_STATUS_VOLUME_NOT_UPGRADED);
	}

	(void) smb_mbc_encodef(
	    &sr->raw_data, "qqqqqll",
	    0,		/* free space start filtering - MUST be 0 */
	    0,		/* free space threshold - MUST be 0 */
	    0,		/* free space stop filtering - MUST be 0 */
	    SMB_QUOTA_UNLIMITED,	/* default quota threshold */
	    SMB_QUOTA_UNLIMITED,	/* default quota limit */
	    FILE_VC_QUOTA_ENFORCE,	/* fs control flag */
	    0);				/* pad bytes */

	return (0);
}
示例#5
0
/*
 * Prepare a response with V3/V4 referral format.
 *
 * For more details, see comments for smb_dfs_encode_refv2() or see
 * MS-DFSC specification.
 */
static uint32_t
smb_dfs_encode_refv3x(smb_request_t *sr, mbuf_chain_t *mbc,
	dfs_info_t *referrals,
    uint16_t ver)
{
	_NOTE(ARGUNUSED(sr))
	uint16_t entsize, rep_bufsize, hdrsize;
	uint16_t server_type;
	uint16_t flags = 0;
	uint16_t path_offs, altpath_offs, netpath_offs;
	uint16_t targetsz, total_targetsz = 0;
	uint16_t dfs_pathsz;
	uint16_t r;

	hdrsize = (ver == DFS_REFERRAL_V3) ? DFS_REFV3_ENTSZ : DFS_REFV4_ENTSZ;
	rep_bufsize = MBC_MAXBYTES(mbc);
	dfs_pathsz = smb_wcequiv_strlen(referrals->i_uncpath) + 2;
	entsize = hdrsize + dfs_pathsz + dfs_pathsz +
	    smb_dfs_referrals_unclen(referrals, 0);

	if (entsize > rep_bufsize) {
		/* need room for at least one referral */
		return (NT_STATUS_BUFFER_OVERFLOW);
	}

	server_type = (referrals->i_type == DFS_OBJECT_ROOT) ?
	    DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT;

	rep_bufsize -= entsize;

	for (r = 0; r < referrals->i_ntargets; r++) {
		path_offs = (referrals->i_ntargets - r) * hdrsize;
		altpath_offs = path_offs + dfs_pathsz;
		netpath_offs = altpath_offs + dfs_pathsz + total_targetsz;
		targetsz = smb_dfs_referrals_unclen(referrals, r);

		if (r != 0) {
			entsize = hdrsize + targetsz;
			if (entsize > rep_bufsize)
				/* silently drop targets that do not fit */
				break;
			rep_bufsize -= entsize;
			flags = 0;
		} else if (ver == DFS_REFERRAL_V4) {
			flags = DFS_ENTFLG_T;
		}

		(void) smb_mbc_encodef(mbc, "wwwwlwww16.",
		    ver, hdrsize, server_type, flags,
		    referrals->i_timeout, path_offs, altpath_offs,
		    netpath_offs);

		total_targetsz += targetsz;
	}

	smb_dfs_encode_targets(mbc, referrals);

	return (NT_STATUS_SUCCESS);
}
示例#6
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);
}
/*
 * FileAttributeTagInformation
 *
 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
 * second dword should be the reparse tag.  Otherwise
 * the tag value should be set to zero.
 * We don't support reparse points, so we set the tag
 * to zero.
 */
static uint32_t
smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi)
{
	_NOTE(ARGUNUSED(qi))
	(void) smb_mbc_encodef(
	    &sr->raw_data, "ll", 0, 0);

	return (0);
}
示例#8
0
/*
 * Encodes DFS path, and target strings which come after fixed header
 * entries.
 *
 * Windows 2000 and earlier set the DFSAlternatePathOffset to point to
 * an 8.3 string representation of the string pointed to by
 * DFSPathOffset if it is not a legal 8.3 string. Otherwise, if
 * DFSPathOffset points to a legal 8.3 string, DFSAlternatePathOffset
 * points to a separate copy of the same string. Windows Server 2003,
 * Windows Server 2008 and Windows Server 2008 R2 set the
 * DFSPathOffset and DFSAlternatePathOffset fields to point to separate
 * copies of the identical string.
 *
 * Following Windows 2003 and later here.
 */
static void
smb_dfs_encode_targets(mbuf_chain_t *mbc, dfs_info_t *referrals)
{
	char *target;
	int r;

	(void) smb_mbc_encodef(mbc, "UU", referrals->i_uncpath,
	    referrals->i_uncpath);

	target = kmem_alloc(MAXPATHLEN, KM_SLEEP);
	for (r = 0; r < referrals->i_ntargets; r++) {
		(void) snprintf(target, MAXPATHLEN, "\\%s\\%s",
		    referrals->i_targets[r].t_server,
		    referrals->i_targets[r].t_share);
		(void) smb_mbc_encodef(mbc, "U", target);
	}
	kmem_free(target, MAXPATHLEN);
}
/*
 * FileAccessInformation
 */
static uint32_t
smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi)
{
	_NOTE(ARGUNUSED(qi))
	smb_ofile_t *of = sr->fid_ofile;

	(void) smb_mbc_encodef(
	    &sr->raw_data, "l",
	    of->f_granted_access);

	return (0);
}
示例#10
0
/*
 * FileInternalInformation
 * See also:
 *	SMB_FILE_INTERNAL_INFORMATION
 */
static uint32_t
smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi)
{
	smb_attr_t *sa = &qi->qi_attr;

	ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID);

	(void) smb_mbc_encodef(
	    &sr->raw_data, "q",
	    sa->sa_vattr.va_nodeid);	/* q */

	return (0);
}
示例#11
0
/*
 * FileFsAttributeInformation
 */
uint32_t
smb2_qfs_attr(smb_request_t *sr)
{
	smb_tree_t *tree = sr->tid_tree;
	char *fsname;
	uint32_t namelen;
	uint32_t FsAttr;

	/* This call is OK on all tree types. */
	switch (tree->t_res_type & STYPE_MASK) {
	case STYPE_IPC:
		fsname = "PIPE";
		break;
	case STYPE_DISKTREE:
		fsname = "NTFS"; /* A lie, but compatible... */
		break;
	case STYPE_PRINTQ:
	case STYPE_DEVICE:
	default: /* gcc -Wuninitialized */
		return (NT_STATUS_INVALID_PARAMETER);
	}
	namelen = smb_wcequiv_strlen(fsname);

	/*
	 * Todo: Store the FsAttributes in the tree object,
	 * then just return that directly here.
	 */
	FsAttr = FILE_CASE_PRESERVED_NAMES;
	if (tree->t_flags & SMB_TREE_UNICODE_ON_DISK)
		FsAttr |= FILE_UNICODE_ON_DISK;
	if (tree->t_flags & SMB_TREE_SUPPORTS_ACLS)
		FsAttr |= FILE_PERSISTENT_ACLS;
	if ((tree->t_flags & SMB_TREE_CASEINSENSITIVE) == 0)
		FsAttr |= FILE_CASE_SENSITIVE_SEARCH;
	if (tree->t_flags & SMB_TREE_STREAMS)
		FsAttr |= FILE_NAMED_STREAMS;
	if (tree->t_flags & SMB_TREE_QUOTA)
		FsAttr |= FILE_VOLUME_QUOTAS;
	if (tree->t_flags & SMB_TREE_SPARSE)
		FsAttr |= FILE_SUPPORTS_SPARSE_FILES;

	(void) smb_mbc_encodef(
	    &sr->raw_data, "lllU",
	    FsAttr,
	    MAXNAMELEN-1,
	    namelen,
	    fsname);

	return (0);
}
示例#12
0
/*
 * FileNameInformation
 * See also:
 *	SMB_QUERY_FILE_NAME_INFO
 *	SMB_FILE_NAME_INFORMATION
 */
static uint32_t
smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi)
{

	ASSERT(qi->qi_namelen > 0);

	(void) smb_mbc_encodef(
	    &sr->raw_data, "llU",
	    0, /* FileIndex	 (l) */
	    qi->qi_namelen,	/* l */
	    qi->qi_name);	/* U */

	return (0);
}
示例#13
0
/*
 * FileCompressionInformation
 * XXX: For now, just say "not compressed".
 */
static uint32_t
smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi)
{
	smb_attr_t *sa = &qi->qi_attr;
	uint16_t CompressionFormat = 0;	/* COMPRESSION_FORMAT_NONE */

	ASSERT(sa->sa_mask & SMB_AT_SIZE);

	(void) smb_mbc_encodef(
	    &sr->raw_data, "qw6.",
	    sa->sa_vattr.va_size,	/* q */
	    CompressionFormat);		/* w */

	return (0);
}
示例#14
0
static void
smb_dfs_encode_hdr(mbuf_chain_t *mbc, dfs_info_t *referrals)
{
	uint16_t path_consumed;
	uint32_t flags;

	path_consumed = smb_wcequiv_strlen(referrals->i_uncpath);
	flags = DFS_HDRFLG_S;
	if (referrals->i_type == DFS_OBJECT_ROOT)
		flags |= DFS_HDRFLG_R;

	/* Fill rep_param_mb in SMB1 caller. */
	(void) smb_mbc_encodef(mbc, "wwl", path_consumed,
	    referrals->i_ntargets, flags);
}
示例#15
0
/*
 * FilePositionInformation
 */
static uint32_t
smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi)
{
	_NOTE(ARGUNUSED(qi))
	smb_ofile_t *of = sr->fid_ofile;
	uint64_t pos;

	mutex_enter(&of->f_mutex);
	pos = of->f_seek_pos;
	mutex_exit(&of->f_mutex);

	(void) smb_mbc_encodef(
	    &sr->raw_data, "q", pos);

	return (0);
}
示例#16
0
int
smb2_encode_header(smb_request_t *sr, boolean_t overwrite)
{
	uint64_t ssnid = sr->smb_uid;
	uint64_t pid_tid_aid; /* pid+tid, or async id */
	int rc;

	if (sr->smb2_hdr_flags & SMB2_FLAGS_ASYNC_COMMAND) {
		pid_tid_aid = sr->smb2_async_id;
	} else {
		pid_tid_aid = sr->smb_pid |
		    ((uint64_t)sr->smb_tid) << 32;
	}

	if (overwrite) {
		rc = smb_mbc_poke(&sr->reply,
		    sr->smb2_reply_hdr,
		    "Nwwlwwllqqq16c",
		    SMB2_HDR_SIZE,		/* w */
		    sr->smb2_credit_charge,	/* w */
		    sr->smb2_status,		/* l */
		    sr->smb2_cmd_code,		/* w */
		    sr->smb2_credit_response,	/* w */
		    sr->smb2_hdr_flags,		/* l */
		    sr->smb2_next_reply,	/* l */
		    sr->smb2_messageid,		/* q */
		    pid_tid_aid,		/* q */
		    ssnid,			/* q */
		    sr->smb2_sig);		/* 16c */
	} else {
		rc = smb_mbc_encodef(&sr->reply,
		    "Nwwlwwllqqq16c",
		    SMB2_HDR_SIZE,		/* w */
		    sr->smb2_credit_charge,	/* w */
		    sr->smb2_status,		/* l */
		    sr->smb2_cmd_code,		/* w */
		    sr->smb2_credit_response,	/* w */
		    sr->smb2_hdr_flags,		/* l */
		    sr->smb2_next_reply,	/* l */
		    sr->smb2_messageid,		/* q */
		    pid_tid_aid,		/* q */
		    ssnid,			/* q */
		    sr->smb2_sig);		/* 16c */
	}

	return (rc);
}
示例#17
0
/*
 * FileStreamInformation
 */
static uint32_t
smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi)
{
	smb_ofile_t *of = sr->fid_ofile;
	smb_attr_t *attr = &qi->qi_attr;
	uint32_t status;

	ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);
	if (of->f_ftype != SMB_FTYPE_DISK) {
		(void) smb_mbc_encodef(
		    &sr->raw_data, "l", 0);
		return (0);
	}

	status = smb_query_stream_info(sr, &sr->raw_data, qi);
	return (status);
}
示例#18
0
static uint32_t
smb_dfs_encode_refv1(smb_request_t *sr, mbuf_chain_t *mbc,
	dfs_info_t *referrals)
{
	_NOTE(ARGUNUSED(sr))
	uint16_t entsize, rep_bufsize;
	uint16_t server_type;
	uint16_t flags = 0;
	uint16_t r;
	char *target;

	rep_bufsize = MBC_MAXBYTES(mbc);

	server_type = (referrals->i_type == DFS_OBJECT_ROOT) ?
	    DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT;

	target = kmem_alloc(MAXPATHLEN, KM_SLEEP);

	for (r = 0; r < referrals->i_ntargets; r++) {
		(void) snprintf(target, MAXPATHLEN, "\\%s\\%s",
		    referrals->i_targets[r].t_server,
		    referrals->i_targets[r].t_share);

		entsize = DFS_REFV1_ENTSZ + smb_wcequiv_strlen(target) + 2;
		if (entsize > rep_bufsize)
			break;

		(void) smb_mbc_encodef(mbc, "wwwwU",
		    DFS_REFERRAL_V1, entsize, server_type, flags, target);
		rep_bufsize -= entsize;
	}

	kmem_free(target, MAXPATHLEN);

	/*
	 * Need room for at least one entry.
	 * Windows will silently drop targets that do not fit in
	 * the response buffer.
	 */
	if (r == 0) {
		return (NT_STATUS_BUFFER_OVERFLOW);
	}

	return (NT_STATUS_SUCCESS);
}
示例#19
0
/*
 * FileStandardInformation
 * See also:
 *	SMB_QUERY_FILE_STANDARD_INFO
 *	SMB_FILE_STANDARD_INFORMATION
 */
static uint32_t
smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi)
{
	smb_attr_t *sa = &qi->qi_attr;

	ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD);

	(void) smb_mbc_encodef(
	    &sr->raw_data, "qqlbbw",
	    sa->sa_allocsz,		/* q */
	    sa->sa_vattr.va_size,	/* q */
	    sa->sa_vattr.va_nlink,	/* l */
	    qi->qi_delete_on_close,	/* b */
	    qi->qi_isdir,		/* b */
	    0); /* reserved */		/* w */

	return (0);
}
示例#20
0
/*
 * FileBasicInformation
 * See also:
 *	case SMB_QUERY_FILE_BASIC_INFO:
 *	case SMB_FILE_BASIC_INFORMATION:
 */
static uint32_t
smb2_qif_basic(smb_request_t *sr, smb_queryinfo_t *qi)
{
	smb_attr_t *sa = &qi->qi_attr;

	ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC);

	(void) smb_mbc_encodef(
	    &sr->raw_data, "TTTTll",
	    &sa->sa_crtime,		/* T */
	    &sa->sa_vattr.va_atime,	/* T */
	    &sa->sa_vattr.va_mtime,	/* T */
	    &sa->sa_vattr.va_ctime,	/* T */
	    sa->sa_dosattr,		/* l */
	    0); /* reserved */		/* l */

	return (0);
}
示例#21
0
/*
 * FileNetworkOpenInformation
 */
static uint32_t
smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi)
{
	smb_attr_t *sa = &qi->qi_attr;

	(void) smb_mbc_encodef(
	    &sr->raw_data, "TTTTqqll",
	    &sa->sa_crtime,		/* T */
	    &sa->sa_vattr.va_atime,	/* T */
	    &sa->sa_vattr.va_mtime,	/* T */
	    &sa->sa_vattr.va_ctime,	/* T */
	    sa->sa_allocsz,		/* q */
	    sa->sa_vattr.va_size,	/* q */
	    sa->sa_dosattr,		/* l */
	    0); /* reserved */		/* l */

	return (0);
}
/*
 * Compose an SMB1 Oplock Break Notification packet, including
 * the SMB1 header and everything, in sr->reply.
 * The caller will send it and free the request.
 */
void
smb1_oplock_break_notification(smb_request_t *sr, uint8_t brk)
{
	smb_ofile_t *ofile = sr->fid_ofile;
	uint16_t fid;
	uint8_t lock_type;
	uint8_t oplock_level;

	switch (brk) {
	default:
		ASSERT(0);
		/* FALLTHROUGH */
	case SMB_OPLOCK_BREAK_TO_NONE:
		oplock_level = 0;
		break;
	case SMB_OPLOCK_BREAK_TO_LEVEL_II:
		oplock_level = 1;
		break;
	}

	sr->smb_com = SMB_COM_LOCKING_ANDX;
	sr->smb_tid = ofile->f_tree->t_tid;
	sr->smb_pid = 0xFFFF;
	sr->smb_uid = 0;
	sr->smb_mid = 0xFFFF;
	fid = ofile->f_fid;
	lock_type = LOCKING_ANDX_OPLOCK_RELEASE;

	(void) smb_mbc_encodef(
	    &sr->reply, "Mb19.wwwwbb3.wbb10.",
	    /*  "\xffSMB"		   M */
	    sr->smb_com,		/* b */
	    /* status, flags, signature	 19. */
	    sr->smb_tid,		/* w */
	    sr->smb_pid,		/* w */
	    sr->smb_uid,		/* w */
	    sr->smb_mid,		/* w */
	    8,		/* word count	   b */
	    0xFF,	/* AndX cmd	   b */
	    /*  AndX reserved, offset	  3. */
	    fid,
	    lock_type,
	    oplock_level);
}
示例#23
0
/*
 * FileFsDeviceInformation
 */
uint32_t
smb2_qfs_device(smb_request_t *sr)
{
	smb_tree_t *tree = sr->tid_tree;
	uint32_t DeviceType;
	uint32_t Characteristics;

	if (!STYPE_ISDSK(tree->t_res_type))
		return (NT_STATUS_INVALID_PARAMETER);

	DeviceType = FILE_DEVICE_DISK;
	Characteristics = FILE_DEVICE_IS_MOUNTED;

	(void) smb_mbc_encodef(
	    &sr->raw_data, "ll",
	    DeviceType,
	    Characteristics);

	return (0);
}
示例#24
0
/*
 * This is to respond to the nt_transact_ioctl to either respond with the
 * number of snapshots, or to respond with the list.  It needs to be sorted
 * before the reply.  If the the max data bytes to return is
 * SMB_VSS_COUNT_SIZE, then all that is requested is the count, otherwise
 * return the count and the list of @GMT tokens (one token for each
 * snapshot).
 */
uint32_t
smb_vss_enum_snapshots(smb_request_t *sr, smb_fsctl_t *fsctl)
{
	uint32_t count = 0;
	char *root_path;
	uint32_t status = NT_STATUS_SUCCESS;
	smb_node_t *tnode;
	smb_gmttoken_response_t snaps;

	ASSERT(sr->tid_tree);
	ASSERT(sr->tid_tree->t_snode);

	if (fsctl->MaxOutputResp < SMB_VSS_COUNT_SIZE)
		return (NT_STATUS_INVALID_PARAMETER);

	tnode = sr->tid_tree->t_snode;
	root_path  = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
	if (smb_node_getmntpath(tnode, root_path, MAXPATHLEN) != 0)
		return (NT_STATUS_INVALID_PARAMETER);

	if (fsctl->MaxOutputResp == SMB_VSS_COUNT_SIZE) {
		count = smb_vss_get_count(sr->tid_tree, root_path);
		if (smb_mbc_encodef(fsctl->out_mbc, "lllw", count, 0,
		    (count * SMB_VSS_GMT_NET_SIZE(sr) +
		    smb_ascii_or_unicode_null_len(sr)), 0) != 0) {
			status = NT_STATUS_INVALID_PARAMETER;
		}
	} else {
		count = fsctl->MaxOutputResp / SMB_VSS_GMT_NET_SIZE(sr);

		smb_vss_get_snapshots(sr->tid_tree, root_path,
		    count, &snaps);

		status = smb_vss_encode_gmttokens(sr, fsctl, count, &snaps);

		smb_vss_get_snapshots_free(&snaps);
	}

	kmem_free(root_path, MAXPATHLEN);
	return (status);
}
示例#25
0
/*
 * FileFsSizeInformation
 */
uint32_t
smb2_qfs_size(smb_request_t *sr)
{
	smb_fssize_t		fssize;
	smb_tree_t *tree = sr->tid_tree;
	int rc;

	if (!STYPE_ISDSK(tree->t_res_type))
		return (NT_STATUS_INVALID_PARAMETER);

	rc = smb_fssize(sr, &fssize);
	if (rc)
		return (smb_errno2status(rc));

	(void) smb_mbc_encodef(
	    &sr->raw_data, "qqll",
	    fssize.fs_caller_units,
	    fssize.fs_caller_avail,
	    fssize.fs_sectors_per_unit,
	    fssize.fs_bytes_per_sector);

	return (0);
}
示例#26
0
/*
 * FileAlternateNameInformation
 * See also:
 *	SMB_QUERY_FILE_ALT_NAME_INFO
 *	SMB_FILE_ALT_NAME_INFORMATION
 */
static uint32_t
smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi)
{
    smb_ofile_t *of = sr->fid_ofile;

    ASSERT(qi->qi_namelen > 0);
    ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID);

    if (of->f_ftype != SMB_FTYPE_DISK)
        return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
    if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0)
        return (NT_STATUS_OBJECT_NAME_NOT_FOUND);

    /* fill in qi->qi_shortname */
    smb_query_shortname(of->f_node, qi);

    (void) smb_mbc_encodef(
        &sr->raw_data, "%lU", sr,
        smb_wcequiv_strlen(qi->qi_shortname),
        qi->qi_shortname);

    return (0);
}
示例#27
0
/*
 * See [MS-DFSC] for details about this command
 */
smb_sdrc_t
smb_com_trans2_get_dfs_referral(smb_request_t *sr, smb_xa_t *xa)
{
	smb_fsctl_t fsctl;
	uint32_t status;
	uint16_t doserr;

	/* This request is only valid over IPC connections */
	if (!STYPE_ISIPC(sr->tid_tree->t_res_type)) {
		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
		    ERROR_ACCESS_DENIED);
		return (SDRC_ERROR);
	}

	fsctl.CtlCode = FSCTL_DFS_GET_REFERRALS;
	fsctl.InputCount = xa->smb_tpscnt;
	fsctl.OutputCount = 0;
	fsctl.MaxOutputResp = xa->smb_mdrcnt;
	fsctl.in_mbc = &xa->req_param_mb;
	fsctl.out_mbc = &xa->rep_data_mb;

	status = smb_dfs_get_referrals(sr, &fsctl);

	/* Out param is the API-level return code. */
	doserr = smb_status2doserr(status);
	(void) smb_mbc_encodef(&xa->rep_param_mb, "w", doserr);

#if 0	/* XXX - Is API-level return code enough? */
	if (status) {
		smbsr_error(sr, NT_STATUS_NO_SUCH_DEVICE, 0, 0);
		return (SDRC_ERROR);
	}
#endif

	return (SDRC_SUCCESS);
}
示例#28
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);
}
示例#30
0
smb_sdrc_t
smb2_read(smb_request_t *sr)
{
	smb_ofile_t *of = NULL;
	smb_vdb_t *vdb = NULL;
	struct mbuf *m = NULL;
	uint16_t StructSize;
	uint8_t Padding;
	uint8_t DataOff;
	uint32_t Length;
	uint64_t Offset;
	smb2fid_t smb2fid;
	uint32_t MinCount;
	uint32_t Channel;
	uint32_t Remaining;
	uint16_t ChanInfoOffset;
	uint16_t ChanInfoLength;
	uint32_t XferCount;
	uint32_t status;
	int rc = 0;

	/*
	 * SMB2 Read request
	 */
	rc = smb_mbc_decodef(
	    &sr->smb_data,
	    "wb.lqqqlllww",
	    &StructSize,		/* w */
	    &Padding,			/* b. */
	    &Length,			/* l */
	    &Offset,			/* q */
	    &smb2fid.persistent,	/* q */
	    &smb2fid.temporal,		/* q */
	    &MinCount,			/* l */
	    &Channel,			/* l */
	    &Remaining,			/* l */
	    &ChanInfoOffset,		/* w */
	    &ChanInfoLength);		/* w */
	if (rc)
		return (SDRC_ERROR);
	if (StructSize != 49)
		return (SDRC_ERROR);

	status = smb2sr_lookup_fid(sr, &smb2fid);
	if (status) {
		smb2sr_put_error(sr, status);
		return (SDRC_SUCCESS);
	}
	of = sr->fid_ofile;

	if (Length > smb2_max_rwsize) {
		smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
		return (SDRC_SUCCESS);
	}
	if (MinCount > Length)
		MinCount = Length;

	/* This is automatically free'd. */
	vdb = smb_srm_zalloc(sr, sizeof (*vdb));
	vdb->vdb_tag = 0;
	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
	vdb->vdb_uio.uio_resid = Length;
	vdb->vdb_uio.uio_loffset = (offset_t)Offset;
	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;

	sr->raw_data.max_bytes = Length;
	m = smb_mbuf_allocate(&vdb->vdb_uio);

	switch (of->f_tree->t_res_type & STYPE_MASK) {
	case STYPE_DISKTREE:
		if (!smb_node_is_dir(of->f_node)) {
			/* Check for conflicting locks. */
			rc = smb_lock_range_access(sr, of->f_node,
			    Offset, Length, B_FALSE);
			if (rc) {
				rc = ERANGE;
				break;
			}
		}
		rc = smb_fsop_read(sr, of->f_cr, of->f_node, &vdb->vdb_uio);
		break;
	case STYPE_IPC:
		rc = smb_opipe_read(sr, &vdb->vdb_uio);
		break;
	default:
	case STYPE_PRINTQ:
		rc = EACCES;
		break;
	}

	/* How much data we moved. */
	XferCount = Length - vdb->vdb_uio.uio_resid;

	sr->raw_data.max_bytes = XferCount;
	smb_mbuf_trim(m, XferCount);
	MBC_ATTACH_MBUF(&sr->raw_data, m);

	/*
	 * Checking the error return _after_ dealing with
	 * the returned data so that if m was allocated,
	 * it will be free'd via sr->raw_data cleanup.
	 */
	if (rc) {
		smb2sr_put_errno(sr, rc);
		return (SDRC_SUCCESS);
	}

	/*
	 * SMB2 Read reply
	 */
	DataOff = SMB2_HDR_SIZE + 16;
	rc = smb_mbc_encodef(
	    &sr->reply,
	    "wb.lllC",
	    17,	/* StructSize */	/* w */
	    DataOff,			/* b. */
	    XferCount,			/* l */
	    0, /* DataRemaining */	/* l */
	    0, /* reserved */		/* l */
	    &sr->raw_data);		/* C */
	if (rc)
		return (SDRC_ERROR);

	mutex_enter(&of->f_mutex);
	of->f_seek_pos = Offset + XferCount;
	mutex_exit(&of->f_mutex);

	return (SDRC_SUCCESS);
}