Exemplo n.º 1
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);
}
Exemplo n.º 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);
}
Exemplo n.º 3
0
smb_sdrc_t
smb_com_create_directory(smb_request_t *sr)
{
	int rc = 0;
	smb_pathname_t *pn = &sr->arg.dirop.fqi.fq_path;

	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
		    ERRDOS, ERROR_ACCESS_DENIED);
		return (SDRC_ERROR);
	}

	smb_pathname_init(sr, pn, pn->pn_path);
	if (!smb_pathname_validate(sr, pn) ||
	    !smb_validate_dirname(sr, pn)) {
		return (SDRC_ERROR);
	}

	if ((rc = smb_common_create_directory(sr)) != 0) {
		smbsr_errno(sr, rc);
		return (SDRC_ERROR);
	}

	rc = smbsr_encode_empty_result(sr);
	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
Exemplo n.º 4
0
/*
 * Add the given share in the specified server.
 * If the share is a disk share, smb_vfs_hold() is
 * invoked to ensure that there is a hold on the
 * corresponding file system before the share is
 * added to shares AVL.
 *
 * If the share is an Autohome share and it is
 * already in the AVL only a reference count for
 * that share is incremented.
 */
static int
smb_kshare_export(smb_server_t *sv, smb_kshare_t *shr)
{
	smb_avl_t	*share_avl;
	smb_kshare_t	*auto_shr;
	vnode_t		*vp;
	int		rc = 0;

	share_avl = &sv->sv_export.e_share_avl;

	if (!STYPE_ISDSK(shr->shr_type)) {
		if ((rc = smb_avl_add(share_avl, shr)) != 0) {
			cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
			    shr->shr_name, rc);
		}

		return (rc);
	}

	if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) {
		if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) == 0) {
			smb_avl_release(share_avl, auto_shr);
			return (EEXIST);
		}

		mutex_enter(&auto_shr->shr_mutex);
		auto_shr->shr_autocnt++;
		mutex_exit(&auto_shr->shr_mutex);
		smb_avl_release(share_avl, auto_shr);
		return (0);
	}

	if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) {
		cmn_err(CE_WARN, "export[%s(%s)]: failed obtaining vnode (%d)",
		    shr->shr_name, shr->shr_path, rc);
		return (rc);
	}

	if ((rc = smb_vfs_hold(&sv->sv_export, vp->v_vfsp)) == 0) {
		if ((rc = smb_avl_add(share_avl, shr)) != 0) {
			cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
			    shr->shr_name, rc);
			smb_vfs_rele(&sv->sv_export, vp->v_vfsp);
		}
	} else {
		cmn_err(CE_WARN, "export[%s(%s)]: failed holding VFS (%d)",
		    shr->shr_name, shr->shr_path, rc);
	}

	VN_RELE(vp);
	return (rc);
}
smb_sdrc_t
smb_com_query_information_disk(smb_request_t *sr)
{
	int			rc;
	struct statvfs64	df;
	fsblkcnt64_t		total_blocks, free_blocks;
	unsigned long		block_size, unit_size;
	unsigned short		blocks_per_unit, bytes_per_block;
	unsigned short		total_units, free_units;

	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
		return (SDRC_ERROR);
	}

	rc = smb_fsop_statfs(sr->user_cr, sr->tid_tree->t_snode, &df);
	if (rc != 0) {
		smbsr_errno(sr, rc);
		return (SDRC_ERROR);
	}

	unit_size = 1;
	block_size = df.f_frsize;
	total_blocks = df.f_blocks;
	free_blocks = df.f_bavail;

	/*
	 * It seems that DOS clients cannot handle block sizes
	 * bigger than 512 KB. So we have to set the block size at
	 * most to 512
	 */

	while (block_size > 512) {
		block_size >>= 1;
		unit_size <<= 1;
	}

	/* adjust blocks and sizes until they fit into a word */

	while (total_blocks >= 0xFFFF) {
		total_blocks >>= 1;
		free_blocks >>= 1;
		if ((unit_size <<= 1) > 0xFFFF) {
			unit_size >>= 1;
			total_blocks = 0xFFFF;
			free_blocks <<= 1;
			break;
		}
	}
smb_sdrc_t
smb_com_query_information(smb_request_t *sr)
{
	char *path = sr->arg.dirop.fqi.fq_path.pn_path;
	uint16_t infolev = SMB_QUERY_INFORMATION;

	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_query_by_path(sr, NULL, infolev, path) != 0)
		return (SDRC_ERROR);

	return (SDRC_SUCCESS);
}
Exemplo n.º 7
0
/*
 * Removes the share specified by 'shrname' from the AVL
 * tree of the given server if it's there.
 *
 * If the share is an Autohome share, the autohome count
 * is decremented and the share is only removed if the
 * count goes to zero.
 *
 * If the share is a disk share, the hold on the corresponding
 * file system is released before removing the share from
 * the AVL tree.
 */
static int
smb_kshare_unexport(smb_server_t *sv, const char *shrname)
{
	smb_avl_t	*share_avl;
	smb_kshare_t	key;
	smb_kshare_t	*shr;
	vnode_t		*vp;
	int		rc;
	boolean_t	auto_unexport;

	share_avl = &sv->sv_export.e_share_avl;

	key.shr_name = (char *)shrname;
	if ((shr = smb_avl_lookup(share_avl, &key)) == NULL)
		return (ENOENT);

	if ((shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
		mutex_enter(&shr->shr_mutex);
		shr->shr_autocnt--;
		auto_unexport = (shr->shr_autocnt == 0);
		mutex_exit(&shr->shr_mutex);
		if (!auto_unexport) {
			smb_avl_release(share_avl, shr);
			return (0);
		}
	}

	if (STYPE_ISDSK(shr->shr_type)) {
		if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) {
			smb_avl_release(share_avl, shr);
			cmn_err(CE_WARN, "unexport[%s]: failed obtaining vnode"
			    " (%d)", shrname, rc);
			return (rc);
		}

		smb_vfs_rele(&sv->sv_export, vp->v_vfsp);
		VN_RELE(vp);
	}

	smb_avl_remove(share_avl, shr);
	smb_avl_release(share_avl, shr);

	return (0);
}
Exemplo n.º 8
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);
}
/*
 * smb_com_trans2_query_path_information
 */
smb_sdrc_t
smb_com_trans2_query_path_information(smb_request_t *sr, smb_xa_t *xa)
{
	uint16_t infolev;
	char *path;

	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
		smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
		    ERRDOS, ERROR_INVALID_FUNCTION);
		return (SDRC_ERROR);
	}

	if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
	    sr, &infolev, &path) != 0)
		return (SDRC_ERROR);

	if (smb_query_by_path(sr, xa, infolev, path) != 0)
		return (SDRC_ERROR);

	return (SDRC_SUCCESS);
}
Exemplo n.º 10
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);
}
Exemplo n.º 11
0
/*
 * smb_com_trans2_find_next2
 *
 *  Client Request                     Value
 *  ================================== =================================
 *
 *  WordCount                          15
 *  SetupCount                         1
 *  Setup[0]                           TRANS2_FIND_NEXT2
 *
 *  Parameter Block Encoding           Description
 *  ================================== =================================
 *
 *  USHORT Sid;                        Search handle
 *  USHORT SearchCount;                Maximum number of entries to
 *                                      return
 *  USHORT InformationLevel;           Levels described in
 *                                      TRANS2_FIND_FIRST2 request
 *  ULONG ResumeKey;                   Value returned by previous find2
 *                                      call
 *  USHORT Flags;                      Additional information: bit set-
 *                                      0 - close search after this
 *                                      request
 *                                      1 - close search if end of search
 *                                      reached
 *                                      2 - return resume keys for each
 *                                      entry found
 *                                      3 - resume/continue from previous
 *                                      ending place
 *                                      4 - find with backup intent
 *  STRING FileName;                   Resume file name
 *
 * Sid is the value returned by a previous successful TRANS2_FIND_FIRST2
 * call.  If Bit3 of Flags is set, then FileName may be the NULL string,
 * since the search is continued from the previous TRANS2_FIND request.
 * Otherwise, FileName must not be more than 256 characters long.
 *
 *  Response Field                     Description
 *  ================================== =================================
 *
 *  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
 *
 *
 * The last parameter in the request is a filename, which is a
 * null-terminated unicode string.
 *
 * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
 *    &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname)
 *
 * The filename parameter is not currently decoded because we
 * expect a 2-byte null but Mac OS 10 clients send a 1-byte null,
 * which leads to a decode error.
 * Thus, we do not support resume by filename.  We treat a request
 * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST.
 */
smb_sdrc_t
smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
{
	int			count;
	uint16_t		odid;
	smb_odir_t		*od;
	smb_find_args_t		args;
	smb_odir_resume_t	odir_resume;

	bzero(&args, sizeof (args));
	bzero(&odir_resume, sizeof (odir_resume));

	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, "%wwwlwu", sr,
	    &odid, &args.fa_maxcount, &args.fa_infolev,
	    &odir_resume.or_cookie, &args.fa_fflag,
	    &odir_resume.or_fname) != 0) {
		return (SDRC_ERROR);
	}

	if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
		sr->user_cr = smb_user_getprivcred(sr->uid_user);

	args.fa_maxdata =
	    smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
	if (args.fa_maxdata == 0)
		return (SDRC_ERROR);

	od = smb_tree_lookup_odir(sr->tid_tree, odid);
	if (od == NULL) {
		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
		    ERRDOS, ERROR_INVALID_HANDLE);
		return (SDRC_ERROR);
	}

	/*
	 * Set the correct position in the directory.
	 *
	 * "Continue from last" is easy, but due to a history of
	 * buggy server implementations, most clients don't use
	 * that method.  The most widely used (and reliable) is
	 * resume by file name.  Unfortunately, that can't really
	 * be fully supported unless your file system stores all
	 * directory entries in some sorted order (like NTFS).
	 * We can partially support resume by name, where the only
	 * name we're ever asked to resume on is the same as the
	 * most recent we returned.  That's always what the client
	 * gives us as the resume name, so we can simply remember
	 * the last name/offset pair and use that to position on
	 * the following FindNext call.  In the unlikely event
	 * that the client asks to resume somewhere else, we'll
	 * use the numeric resume key, and hope the client gives
	 * correctly uses one of the resume keys we provided.
	 */
	if (args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) {
		odir_resume.or_type = SMB_ODIR_RESUME_CONT;
	} else {
		odir_resume.or_type = SMB_ODIR_RESUME_FNAME;
	}
	smb_odir_resume_at(od, &odir_resume);

	count = smb_trans2_find_entries(sr, xa, od, &args);
	if (count == -1) {
		smb_odir_close(od);
		smb_odir_release(od);
		return (SDRC_ERROR);
	}

	if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
	    (args.fa_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, "wwww",
	    count,	/* Search Count */
	    args.fa_eos, /* End Of Search */
	    0,		/* EA Error Offset */
	    args.fa_lno); /* Last Name Offset */

	return (SDRC_SUCCESS);
}
Exemplo n.º 12
0
/*
 * 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;
	smb_pathname_t	*pn;
	smb_odir_t	*od;
	smb_find_args_t	args;
	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);
	}

	pn = &sr->arg.dirop.fqi.fq_path;

	if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr,
	    &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev,
	    &pn->pn_path) != 0) {
		return (SDRC_ERROR);
	}

	smb_pathname_init(sr, pn, pn->pn_path);
	if (!smb_pathname_validate(sr, pn))
		return (-1);

	if (smb_is_stream_name(pn->pn_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);

	odid = smb_odir_open(sr, pn->pn_path, sattr, odir_flags);
	if (odid == 0) {
		if (sr->smb_error.status == NT_STATUS_OBJECT_PATH_NOT_FOUND) {
			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
			    ERRDOS, ERROR_FILE_NOT_FOUND);
		}
		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);

	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) ||
	    (args.fa_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,	/* Search ID */
	    count,	/* Search Count */
	    args.fa_eos, /* End Of Search */
	    0,		/* EA Error Offset */
	    args.fa_lno); /* Last Name Offset */

	return (SDRC_SUCCESS);
}
Exemplo n.º 13
0
smb_sdrc_t
smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa)
{
	struct open_param *op = &sr->arg.open;
	uint32_t	creation_time;
	uint32_t	alloc_size;
	uint16_t	flags;
	uint16_t	file_attr;
	int		rc;

	bzero(op, sizeof (sr->arg.open));

	rc = smb_mbc_decodef(&xa->req_param_mb, "%wwwwlwl10.u",
	    sr, &flags, &op->omode, &op->fqi.fq_sattr, &file_attr,
	    &creation_time, &op->ofun, &alloc_size, &op->fqi.fq_path.pn_path);
	if (rc != 0)
		return (SDRC_ERROR);

	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->dattr = file_attr;
	op->dsize = alloc_size;
	op->create_options = FILE_NON_DIRECTORY_FILE;

	op->desired_access = smb_omode_to_amask(op->omode);
	op->share_access = smb_denymode_to_sharemode(op->omode,
	    op->fqi.fq_path.pn_path);

	op->create_disposition = smb_ofun_to_crdisposition(op->ofun);
	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION)
		op->create_disposition = FILE_CREATE;

	if (op->omode & SMB_DA_WRITE_THROUGH)
		op->create_options |= FILE_WRITE_THROUGH;

	if (sr->smb_flg & SMB_FLAGS_OPLOCK) {
		if (sr->smb_flg & SMB_FLAGS_OPLOCK_NOTIFY_ANY)
			op->op_oplock_level = SMB_OPLOCK_BATCH;
		else
			op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
	} else {
		op->op_oplock_level = SMB_OPLOCK_NONE;
	}

	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
		return (SDRC_ERROR);

	if (op->op_oplock_level != SMB_OPLOCK_NONE)
		op->action_taken |= SMB_OACT_LOCK;
	else
		op->action_taken &= ~SMB_OACT_LOCK;

	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;

	if (!STYPE_ISDSK(sr->tid_tree->t_res_type))
		op->dsize = 0;

	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwllwwwwlwl",
	    sr->smb_fid,
	    file_attr,
	    (uint32_t)0,	/* creation time */
	    (uint32_t)op->dsize,
	    op->omode,
	    op->ftype,
	    op->devstate,
	    op->action_taken,
	    op->fileid,
	    (uint16_t)0,	/* EA error offset */
	    (uint32_t)0);	/* EA list length */

	return (SDRC_SUCCESS);
}
Exemplo n.º 14
0
smb_sdrc_t
smb_com_open_andx(smb_request_t *sr)
{
	struct open_param	*op = &sr->arg.open;
	uint16_t		file_attr;
	smb_attr_t		attr;
	int rc;

	op->desired_access = smb_omode_to_amask(op->omode);
	op->share_access = smb_denymode_to_sharemode(op->omode,
	    op->fqi.fq_path.pn_path);

	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
		smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
		return (SDRC_ERROR);
	}

	op->create_options = FILE_NON_DIRECTORY_FILE;
	if (op->omode & SMB_DA_WRITE_THROUGH)
		op->create_options |= FILE_WRITE_THROUGH;

	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
		return (SDRC_ERROR);

	if (smb_open_dsize_check && op->dsize > UINT_MAX) {
		smbsr_error(sr, 0, ERRDOS, ERRbadaccess);
		return (SDRC_ERROR);
	}

	if (op->op_oplock_level != SMB_OPLOCK_NONE)
		op->action_taken |= SMB_OACT_LOCK;
	else
		op->action_taken &= ~SMB_OACT_LOCK;

	file_attr = op->dattr & FILE_ATTRIBUTE_MASK;
	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {

		smb_node_t *node = sr->fid_ofile->f_node;
		if (smb_node_getattr(sr, node, &attr) != 0) {
			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
			    ERRDOS, ERROR_INTERNAL_ERROR);
			return (SDRC_ERROR);
		}

		rc = smbsr_encode_result(sr, 15, 0,
		    "bb.wwwllwwwwl2.w",
		    15,
		    sr->andx_com, VAR_BCC,
		    sr->smb_fid,
		    file_attr,
		    smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
		    (uint32_t)op->dsize,
		    op->omode, op->ftype,
		    op->devstate,
		    op->action_taken, op->fileid,
		    0);
	} else {
		rc = smbsr_encode_result(sr, 15, 0,
		    "bb.wwwllwwwwl2.w",
		    15,
		    sr->andx_com, VAR_BCC,
		    sr->smb_fid,
		    file_attr,
		    0L,
		    0L,
		    op->omode, op->ftype,
		    op->devstate,
		    op->action_taken, op->fileid,
		    0);
	}

	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
Exemplo n.º 15
0
smb_sdrc_t
smb_com_delete_directory(smb_request_t *sr)
{
	int rc;
	uint32_t flags = 0;
	smb_fqi_t *fqi;
	smb_node_t *tnode;

	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
		    ERRDOS, ERROR_ACCESS_DENIED);
		return (SDRC_ERROR);
	}

	fqi = &sr->arg.dirop.fqi;
	tnode = sr->tid_tree->t_snode;

	smb_pathname_init(sr, &fqi->fq_path, fqi->fq_path.pn_path);
	if (!smb_pathname_validate(sr, &fqi->fq_path) ||
	    !smb_validate_dirname(sr, &fqi->fq_path)) {
		return (SDRC_ERROR);
	}

	rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
	    tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);

	if (rc != 0) {
		smbsr_errno(sr, rc);
		return (SDRC_ERROR);
	}

	rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
	    tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
	if (rc != 0) {
		if (rc == ENOENT)
			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
			    ERRDOS, ERROR_FILE_NOT_FOUND);
		else
			smbsr_errno(sr, rc);
		smb_node_release(fqi->fq_dnode);
		return (SDRC_ERROR);
	}

	/*
	 * Delete should fail if this is the root of a share
	 * or a DFS link
	 */
	if ((fqi->fq_fnode == tnode) || smb_node_is_dfslink(fqi->fq_fnode)) {
		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
		    ERRDOS, ERROR_ACCESS_DENIED);
		smb_node_release(fqi->fq_dnode);
		smb_node_release(fqi->fq_fnode);
		return (SDRC_ERROR);
	}

	if (!smb_node_is_dir(fqi->fq_fnode)) {
		smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
		    ERRDOS, ERROR_PATH_NOT_FOUND);
		smb_node_release(fqi->fq_dnode);
		smb_node_release(fqi->fq_fnode);
		return (SDRC_ERROR);
	}

	/*
	 * Using kcred because we just want the DOS attrs
	 * and don't want access errors for this.
	 */
	fqi->fq_fattr.sa_mask = SMB_AT_DOSATTR;
	rc = smb_node_getattr(sr, fqi->fq_fnode, zone_kcred(), NULL,
	    &fqi->fq_fattr);
	if (rc != 0) {
		smbsr_errno(sr, rc);
		smb_node_release(fqi->fq_dnode);
		smb_node_release(fqi->fq_fnode);
		return (SDRC_ERROR);
	}

	if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
	    (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
	    != NT_STATUS_SUCCESS)) {
		smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
		    ERRDOS, ERROR_ACCESS_DENIED);
		smb_node_release(fqi->fq_dnode);
		smb_node_release(fqi->fq_fnode);
		return (SDRC_ERROR);
	}

	if (SMB_TREE_SUPPORTS_CATIA(sr))
		flags |= SMB_CATIA;

	rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
	    fqi->fq_fnode->od_name, flags);

	smb_node_release(fqi->fq_fnode);
	smb_node_release(fqi->fq_dnode);

	if (rc != 0) {
		if (rc == EEXIST)
			smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
			    ERRDOS, ERROR_DIR_NOT_EMPTY);
		else
			smbsr_errno(sr, rc);
		return (SDRC_ERROR);
	}

	rc = smbsr_encode_empty_result(sr);
	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);
}
Exemplo n.º 17
0
/*
 * Allocate a tree.
 */
static smb_tree_t *
smb_tree_alloc(
    smb_user_t		*user,
    const smb_share_t	*si,
    int32_t		stype,
    smb_node_t		*snode,
    uint32_t access)
{
	smb_tree_t	*tree;
	uint16_t	tid;

	if (smb_idpool_alloc(&user->u_tid_pool, &tid))
		return (NULL);

	tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP);
	bzero(tree, sizeof (smb_tree_t));

	if (STYPE_ISDSK(stype)) {
		if (smb_tree_getattr(si, snode, tree) != 0) {
			smb_idpool_free(&user->u_tid_pool, tid);
			kmem_cache_free(user->u_server->si_cache_tree, tree);
			return (NULL);
		}
	}

	if (smb_idpool_constructor(&tree->t_fid_pool)) {
		smb_idpool_free(&user->u_tid_pool, tid);
		kmem_cache_free(user->u_server->si_cache_tree, tree);
		return (NULL);
	}

	if (smb_idpool_constructor(&tree->t_odid_pool)) {
		smb_idpool_destructor(&tree->t_fid_pool);
		smb_idpool_free(&user->u_tid_pool, tid);
		kmem_cache_free(user->u_server->si_cache_tree, tree);
		return (NULL);
	}

	smb_llist_constructor(&tree->t_ofile_list, sizeof (smb_ofile_t),
	    offsetof(smb_ofile_t, f_lnd));

	smb_llist_constructor(&tree->t_odir_list, sizeof (smb_odir_t),
	    offsetof(smb_odir_t, d_lnd));

	(void) strlcpy(tree->t_sharename, si->shr_name,
	    sizeof (tree->t_sharename));
	(void) strlcpy(tree->t_resource, si->shr_path,
	    sizeof (tree->t_resource));

	mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL);

	tree->t_user = user;
	tree->t_session = user->u_session;
	tree->t_server = user->u_server;
	tree->t_refcnt = 1;
	tree->t_tid = tid;
	tree->t_res_type = stype;
	tree->t_state = SMB_TREE_STATE_CONNECTED;
	tree->t_magic = SMB_TREE_MAGIC;
	tree->t_access = access;
	tree->t_connect_time = gethrestime_sec();

	/* if FS is readonly, enforce that here */
	if (tree->t_flags & SMB_TREE_READONLY)
		tree->t_access &= ~ACE_ALL_WRITE_PERMS;

	if (STYPE_ISDSK(stype)) {
		smb_node_ref(snode);
		tree->t_snode = snode;
		tree->t_acltype = smb_fsop_acltype(snode);
	}

	smb_llist_enter(&user->u_tree_list, RW_WRITER);
	smb_llist_insert_head(&user->u_tree_list, tree);
	smb_llist_exit(&user->u_tree_list);
	atomic_inc_32(&user->u_session->s_tree_cnt);
	atomic_inc_32(&user->u_server->sv_open_trees);

	return (tree);
}
smb_sdrc_t
smb_com_nt_create_andx(struct smb_request *sr)
{
	struct open_param	*op = &sr->arg.open;
	unsigned char		OplockLevel;
	unsigned char		DirFlag;
	smb_attr_t		attr;
	smb_node_t		*node;
	int rc;

	if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
	    !(op->desired_access & DELETE)) {
		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
		    ERRDOS, ERRbadaccess);
		return (SDRC_ERROR);
	}

	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
		    ERRDOS, ERRbadaccess);
		return (SDRC_ERROR);
	}

	if (op->dattr & FILE_FLAG_WRITE_THROUGH)
		op->create_options |= FILE_WRITE_THROUGH;

	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
		op->create_options |= FILE_DELETE_ON_CLOSE;

	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;

	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
		sr->user_cr = smb_user_getprivcred(sr->uid_user);

	if (op->rootdirfid == 0) {
		op->fqi.fq_dnode = sr->tid_tree->t_snode;
	} else {
		op->dir = smb_ofile_lookup_by_fid(sr->tid_tree,
		    (uint16_t)op->rootdirfid);
		if (op->dir == NULL) {
			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
			    ERRDOS, ERRbadfid);
			return (SDRC_ERROR);
		}
		op->fqi.fq_dnode = op->dir->f_node;
	}

	if (smb_common_open(sr) != NT_STATUS_SUCCESS)
		return (SDRC_ERROR);

	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
		switch (op->op_oplock_level) {
		case SMB_OPLOCK_EXCLUSIVE:
			OplockLevel = 1;
			break;
		case SMB_OPLOCK_BATCH:
			OplockLevel = 2;
			break;
		case SMB_OPLOCK_LEVEL_II:
			OplockLevel = 3;
			break;
		case SMB_OPLOCK_NONE:
		default:
			OplockLevel = 0;
			break;
		}

		if (op->create_options & FILE_DELETE_ON_CLOSE)
			smb_ofile_set_delete_on_close(sr->fid_ofile);

		node = sr->fid_ofile->f_node;
		DirFlag = smb_node_is_dir(node) ? 1 : 0;
		if (smb_node_getattr(sr, node, &attr) != 0) {
			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
			    ERRDOS, ERROR_INTERNAL_ERROR);
			return (SDRC_ERROR);
		}

		rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlTTTTlqqwwbw",
		    34,
		    sr->andx_com,
		    0x67,
		    OplockLevel,
		    sr->smb_fid,
		    op->action_taken,
		    &attr.sa_crtime,
		    &attr.sa_vattr.va_atime,
		    &attr.sa_vattr.va_mtime,
		    &attr.sa_vattr.va_ctime,
		    op->dattr & FILE_ATTRIBUTE_MASK,
		    attr.sa_allocsz,
		    attr.sa_vattr.va_size,
		    op->ftype,
		    op->devstate,
		    DirFlag,
		    0);
	} else {
		/* Named PIPE */
		OplockLevel = 0;
		rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlqqqqlqqwwbw",
		    34,
		    sr->andx_com,
		    0x67,
		    OplockLevel,
		    sr->smb_fid,
		    op->action_taken,
		    0LL,
		    0LL,
		    0LL,
		    0LL,
		    FILE_ATTRIBUTE_NORMAL,
		    0x1000LL,
		    0LL,
		    op->ftype,
		    op->devstate,
		    0,
		    0);
	}

	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}