smb_sdrc_t
smb_com_query_information(smb_request_t *sr)
{
	uint16_t infolev = SMB_QUERY_INFORMATION;

	if (STYPE_ISIPC(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) != 0)
		return (SDRC_ERROR);

	return (SDRC_SUCCESS);
}
/*
 * 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;
	smb_fqi_t	*fqi = &sr->arg.dirop.fqi;

	if (STYPE_ISIPC(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, &fqi->fq_path.pn_path) != 0)
		return (SDRC_ERROR);

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

	return (SDRC_SUCCESS);
}
Exemple #3
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);
}
Exemple #4
0
int
smb_pathname_reduce(
    smb_request_t	*sr,
    cred_t		*cred,
    const char		*path,
    smb_node_t		*share_root_node,
    smb_node_t		*cur_node,
    smb_node_t		**dir_node,
    char		*last_component)
{
	smb_node_t	*root_node;
	pathname_t	ppn;
	char		*usepath;
	int		lookup_flags = FOLLOW;
	int 		trailing_slash = 0;
	int		err = 0;
	int		len;
	smb_node_t	*vss_cur_node;
	smb_node_t	*vss_root_node;
	smb_node_t	*local_cur_node;
	smb_node_t	*local_root_node;

	ASSERT(dir_node);
	ASSERT(last_component);

	*dir_node = NULL;
	*last_component = '\0';
	vss_cur_node = NULL;
	vss_root_node = NULL;

	if (sr && sr->tid_tree) {
		if (STYPE_ISIPC(sr->tid_tree->t_res_type))
			return (EACCES);
	}

	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
		lookup_flags |= FIGNORECASE;

	if (path == NULL)
		return (EINVAL);

	if (*path == '\0')
		return (ENOENT);

	usepath = kmem_alloc(MAXPATHLEN, KM_SLEEP);

	if ((len = strlcpy(usepath, path, MAXPATHLEN)) >= MAXPATHLEN) {
		kmem_free(usepath, MAXPATHLEN);
		return (ENAMETOOLONG);
	}

	(void) strsubst(usepath, '\\', '/');

	if (share_root_node)
		root_node = share_root_node;
	else
		root_node = sr->sr_server->si_root_smb_node;

	if (cur_node == NULL)
		cur_node = root_node;

	local_cur_node = cur_node;
	local_root_node = root_node;

	if (SMB_TREE_IS_DFSROOT(sr) && (sr->smb_flg2 & SMB_FLAGS2_DFS)) {
		err = smb_pathname_dfs_preprocess(sr, usepath, MAXPATHLEN);
		if (err != 0) {
			kmem_free(usepath, MAXPATHLEN);
			return (err);
		}
		len = strlen(usepath);
	}

	if (sr && (sr->smb_flg2 & SMB_FLAGS2_REPARSE_PATH)) {
		err = smb_vss_lookup_nodes(sr, root_node, cur_node,
		    usepath, &vss_cur_node, &vss_root_node);

		if (err != 0) {
			kmem_free(usepath, MAXPATHLEN);
			return (err);
		}

		len = strlen(usepath);
		local_cur_node = vss_cur_node;
		local_root_node = vss_root_node;
	}

	if (usepath[len - 1] == '/')
		trailing_slash = 1;

	(void) strcanon(usepath, "/");

	(void) pn_alloc(&ppn);

	if ((err = pn_set(&ppn, usepath)) != 0) {
		(void) pn_free(&ppn);
		kmem_free(usepath, MAXPATHLEN);
		if (vss_cur_node != NULL)
			(void) smb_node_release(vss_cur_node);
		if (vss_root_node != NULL)
			(void) smb_node_release(vss_root_node);
		return (err);
	}

	/*
	 * If a path does not have a trailing slash, strip off the
	 * last component.  (We only need to return an smb_node for
	 * the second to last component; a name is returned for the
	 * last component.)
	 */

	if (trailing_slash) {
		(void) strlcpy(last_component, ".", MAXNAMELEN);
	} else {
		(void) pn_setlast(&ppn);
		(void) strlcpy(last_component, ppn.pn_path, MAXNAMELEN);
		ppn.pn_path[0] = '\0';
	}

	if ((strcmp(ppn.pn_buf, "/") == 0) || (ppn.pn_buf[0] == '\0')) {
		smb_node_ref(local_cur_node);
		*dir_node = local_cur_node;
	} else {
		err = smb_pathname(sr, ppn.pn_buf, lookup_flags,
		    local_root_node, local_cur_node, NULL, dir_node, cred);
	}

	(void) pn_free(&ppn);
	kmem_free(usepath, MAXPATHLEN);

	/*
	 * Prevent traversal to another file system if mount point
	 * traversal is disabled.
	 *
	 * Note that we disregard whether the traversal of the path went
	 * outside of the file system and then came back (say via a link).
	 * This means that only symlinks that are expressed relatively to
	 * the share root work.
	 *
	 * share_root_node is NULL when mapping a share, so we disregard
	 * that case.
	 */

	if ((err == 0) && share_root_node) {
		if (share_root_node->vp->v_vfsp != (*dir_node)->vp->v_vfsp) {
			err = EACCES;
			if ((sr) && (sr)->tid_tree &&
			    smb_tree_has_feature((sr)->tid_tree,
			    SMB_TREE_TRAVERSE_MOUNTS))
				err = 0;
		}
	}

	if (err) {
		if (*dir_node) {
			(void) smb_node_release(*dir_node);
			*dir_node = NULL;
		}
		*last_component = 0;
	}

	if (vss_cur_node != NULL)
		(void) smb_node_release(vss_cur_node);
	if (vss_root_node != NULL)
		(void) smb_node_release(vss_root_node);

	return (err);
}
Exemple #5
0
smb_sdrc_t
smb_com_check_directory(smb_request_t *sr)
{
	int rc;
	smb_fqi_t *fqi;
	smb_node_t *tnode;
	smb_node_t *node;
	char *path;
	smb_pathname_t *pn;

	if (STYPE_ISIPC(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;
	pn = &fqi->fq_path;

	if (pn->pn_path[0] == '\0') {
		rc = smbsr_encode_empty_result(sr);
		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
	}

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

	path = pn->pn_path;
	tnode = sr->tid_tree->t_snode;

	rc = smb_pathname_reduce(sr, sr->user_cr, 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);
	smb_node_release(fqi->fq_dnode);
	if (rc != 0) {
		if (rc == ENOENT)
			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
			    ERRDOS, ERROR_PATH_NOT_FOUND);
		else
			smbsr_errno(sr, rc);
		return (SDRC_ERROR);
	}

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

	if ((sr->smb_flg2 & SMB_FLAGS2_DFS) && smb_node_is_dfslink(node)) {
		smbsr_error(sr, NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
		smb_node_release(node);
		return (SDRC_ERROR);
	}

	rc = smb_fsop_access(sr, sr->user_cr, node, FILE_TRAVERSE);

	smb_node_release(node);

	if (rc != 0) {
		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
		    ERRDOS, ERROR_ACCESS_DENIED);
		return (SDRC_ERROR);
	}

	rc = smbsr_encode_empty_result(sr);
	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
Exemple #6
0
/*
 * See [MS-DFSC] for details about this command
 */
uint32_t
smb_dfs_get_referrals(smb_request_t *sr, smb_fsctl_t *fsctl)
{
	dfs_info_t *referrals;
	dfs_referral_response_t refrsp;
	dfs_reftype_t reftype;
	char *path;
	uint16_t maxver;
	uint32_t status;
	int rc;

	/*
	 * The caller checks this, because the error reporting method
	 * varies across SMB versions.
	 */
	ASSERT(STYPE_ISIPC(sr->tid_tree->t_res_type));

	/*
	 * XXX Instead of decoding the referral request and encoding
	 * the response here (in-kernel) we could pass the given
	 * request buffer in our door call, and let that return the
	 * response buffer ready to stuff into out_mbc.  That would
	 * allow all this decoding/encoding to happen at user-level.
	 * (and most of this file would go away. :-)
	 */
	switch (fsctl->CtlCode) {
	case FSCTL_DFS_GET_REFERRALS:
		/*
		 * Input data is (w) MaxReferralLevel, (U) path
		 */
		rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",
		    sr, &maxver, &path);
		if (rc != 0)
			return (NT_STATUS_INVALID_PARAMETER);
		break;

	case FSCTL_DFS_GET_REFERRALS_EX: /* XXX - todo */
	default:
		return (NT_STATUS_NOT_SUPPORTED);
	}

	reftype = smb_dfs_get_reftype((const char *)path);
	switch (reftype) {
	case DFS_REFERRAL_INVALID:
		/* Need to check the error for this case */
		return (NT_STATUS_INVALID_PARAMETER);

	case DFS_REFERRAL_DOMAIN:
	case DFS_REFERRAL_DC:
		/* MS-DFSC: this error is returned by non-DC root */
		return (NT_STATUS_INVALID_PARAMETER);

	case DFS_REFERRAL_SYSVOL:
		/* MS-DFSC: this error is returned by non-DC root */
		return (NT_STATUS_NO_SUCH_DEVICE);

	default:
		break;
	}

	status = smb_dfs_referrals_get(sr, path, reftype, &refrsp);
	if (status != NT_STATUS_SUCCESS)
		return (status);

	referrals = &refrsp.rp_referrals;
	smb_dfs_encode_hdr(fsctl->out_mbc, referrals);

	/*
	 * Server may respond with any referral version at or below
	 * the maximum specified in the request.
	 */
	switch (maxver) {
	case DFS_REFERRAL_V1:
		status = smb_dfs_encode_refv1(sr, fsctl->out_mbc, referrals);
		break;

	case DFS_REFERRAL_V2:
		status = smb_dfs_encode_refv2(sr, fsctl->out_mbc, referrals);
		break;

	case DFS_REFERRAL_V3:
		status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
		    DFS_REFERRAL_V3);
		break;

	case DFS_REFERRAL_V4:
	default:
		status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
		    DFS_REFERRAL_V4);
		break;
	}

	smb_dfs_referrals_free(&refrsp);

	return (status);
}