view usr/src/uts/common/fs/smbsrv/smb_tree_connect.c @ 21416:fe2f621c52e3

1841 SMB dtrace provider is incomplete 11180 SMB2 IOCTL FSCTL_LMR_REQUEST_RESILIENCY Returns Incorrect Response Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com> Reviewed by: Evan Layton <evan.layton@nexenta.com> Reviewed by: Matt Barden <matt.barden@nexenta.com> Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com> Approved by: Richard Lowe <richlowe@richlowe.net>
author Gordon Ross <gwr@nexenta.com>
date Wed, 27 Nov 2013 23:58:32 -0500
parents f9e465f381e1
children b5c798ab332f
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
 */

#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_share.h>

static void
smb_tcon_puterror(smb_request_t *sr, uint32_t status)
{

	switch (status) {

	case NT_STATUS_BAD_NETWORK_NAME:
		/* Intentional status=0 */
		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
		break;

	case NT_STATUS_ACCESS_DENIED:
		smbsr_error(sr, status, ERRSRV, ERRaccess);
		break;

	case NT_STATUS_BAD_DEVICE_TYPE:
		smbsr_error(sr, status, ERRDOS, ERROR_BAD_DEV_TYPE);
		break;

	default:
	case NT_STATUS_INTERNAL_ERROR:
		/* Intentional status=0 */
		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
		break;
	}
}

/*
 * SmbTreeConnect: Map a share to a tree and obtain a tree-id (TID).
 *
 * Client Request                     Description
 * ================================== =================================
 *
 * UCHAR WordCount;                   Count of parameter words = 0
 * USHORT ByteCount;                  Count of data bytes;    min = 4
 * UCHAR BufferFormat1;               0x04
 * STRING Path[];                     Server name and share name
 * UCHAR BufferFormat2;               0x04
 * STRING Password[];                 Password
 * UCHAR BufferFormat3;               0x04
 * STRING Service[];                  Service name
 *
 * The CIFS server responds with:
 *
 * Server Response                  Description
 * ================================ =================================
 *
 * UCHAR WordCount;                 Count of parameter words = 2
 * USHORT MaxBufferSize;            Max size message the server handles
 * USHORT Tid;                      Tree ID
 * USHORT ByteCount;                Count of data bytes = 0
 *
 * If the negotiated dialect is MICROSOFT NETWORKS 1.03 or earlier,
 * MaxBufferSize in the response message indicates the maximum size
 * message that the server can handle.  The client should not generate
 * messages, nor expect to receive responses, larger than this.  This
 * must be constant for a given server. For newer dialects, this field
 * is ignored.
 */
smb_sdrc_t
smb_pre_tree_connect(smb_request_t *sr)
{
	smb_arg_tcon_t	*tcon = &sr->sr_tcon;
	int		rc;

	/*
	 * Perhaps this should be "%A.sA" now that unicode is enabled.
	 */
	rc = smbsr_decode_data(sr, "%AAA", sr, &tcon->path,
	    &tcon->password, &tcon->service);

	tcon->flags = 0;
	tcon->optional_support = 0;

	DTRACE_SMB_START(op__TreeConnect, smb_request_t *, sr);

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

void
smb_post_tree_connect(smb_request_t *sr)
{
	DTRACE_SMB_DONE(op__TreeConnect, smb_request_t *, sr);
}

smb_sdrc_t
smb_com_tree_connect(smb_request_t *sr)
{
	uint32_t status;
	int rc;

	status = smb_tree_connect(sr);
	if (status) {
		smb_tcon_puterror(sr, status);
		return (SDRC_ERROR);
	}

	rc = smbsr_encode_result(sr, 2, 0, "bwww",
	    2,				/* wct */
	    (WORD)smb_maxbufsize,	/* MaxBufferSize */
	    sr->smb_tid,		/* TID */
	    0);				/* bcc */

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

/*
 * SmbTreeConnectX: Map a share to a tree and obtain a tree-id (TID).
 *
 * Client Request                     Description
 * =================================  =================================
 *
 * UCHAR WordCount;                   Count of parameter words = 4
 * UCHAR AndXCommand;                 Secondary (X) command; 0xFF = none
 * UCHAR AndXReserved;                Reserved (must be 0)
 * USHORT AndXOffset;                 Offset to next command WordCount
 * USHORT Flags;                      Additional information
 *                                    bit 0 set = disconnect Tid
 * USHORT PasswordLength;             Length of Password[]
 * USHORT ByteCount;                  Count of data bytes;    min = 3
 * UCHAR Password[];                  Password
 * STRING Path[];                     Server name and share name
 * STRING Service[];                  Service name
 *
 * If the negotiated dialect is LANMAN1.0 or later, then it is a protocol
 * violation for the client to send this message prior to a successful
 * SMB_COM_SESSION_SETUP_ANDX, and the server ignores Password.
 *
 * If the negotiated dialect is prior to LANMAN1.0 and the client has not
 * sent a successful SMB_COM_SESSION_SETUP_ANDX request when the tree
 * connect arrives, a user level security mode server must nevertheless
 * validate the client's credentials.
 *
 * Flags (prefix with TREE_CONNECT_ANDX_):
 * ==========================  ========================================
 * 0x0001 DISCONECT_TID        The tree specified by TID in the SMB header
 *                             should be disconnected - disconnect errors
 *                             should be ignored.
 *
 * 0x0004 EXTENDED_SIGNATURES  Client request for signing key protection.
 *
 * 0x0008 EXTENDED_RESPONSE    Client request for extended information.
 *
 * Path follows UNC style syntax (\\server\share) and indicates the name
 * of the resource to which the client wishes to connect.
 *
 * Because Password may be an authentication response, it is a variable
 * length field with the length specified by PasswordLength.   If
 * authentication is not being used, Password should be a null terminated
 * ASCII string with PasswordLength set to the string size including the
 * terminating null.
 *
 * The server can enforce whatever policy it desires to govern share
 * access.  Administrative privilege is required for administrative
 * shares (C$, etc.).
 *
 * The Service component indicates the type of resource the client
 * intends to access.  Valid values are:
 *
 * Service   Description               Earliest Dialect Allowed
 * ========  ========================  ================================
 *
 * A:        disk share                PC NETWORK PROGRAM 1.0
 * LPT1:     printer                   PC NETWORK PROGRAM 1.0
 * IPC       named pipe                MICROSOFT NETWORKS 3.0
 * COMM      communications device     MICROSOFT NETWORKS 3.0
 * ?????     any type of device        MICROSOFT NETWORKS 3.0
 *
 * If the negotiated dialect is earlier than DOS LANMAN2.1, the response to
 * this SMB is:
 *
 * Server Response                  Description
 * ================================ ===================================
 *
 * UCHAR WordCount;                 Count of parameter words = 2
 * UCHAR AndXCommand;               Secondary (X) command;  0xFF = none
 * UCHAR AndXReserved;              Reserved (must be 0)
 * USHORT AndXOffset;               Offset to next command WordCount
 * USHORT ByteCount;                Count of data bytes;    min = 3
 *
 * If the negotiated is DOS LANMAN2.1 or later, the response to this SMB
 * is:
 *
 * Server Response                  Description
 * ================================ ===================================
 *
 * UCHAR WordCount;                 Count of parameter words = 3
 * UCHAR AndXCommand;               Secondary (X) command;  0xFF = none
 * UCHAR AndXReserved;              Reserved (must be 0)
 * USHORT AndXOffset;               Offset to next command WordCount
 * USHORT OptionalSupport;          Optional support bits
 * USHORT ByteCount;                Count of data bytes;    min = 3
 * UCHAR Service[];                 Service type connected to.  Always
 *                                   ANSII.
 * STRING NativeFileSystem[];       Native file system for this tree
 *
 * NativeFileSystem is the name of the filesystem; values to be expected
 * include FAT, NTFS, etc.
 *
 * OptionalSupport:
 * ==============================  ==========================
 * 0x0001 SMB_SUPPORT_SEARCH_BITS  The server supports the use of Search
 *                                 Attributes in client requests.
 * 0x0002 SMB_SHARE_IS_IN_DFS      The share is managed by DFS.
 * 0x000C SMB_CSC_MASK             Offline-caching mask - see CSC flags.
 * 0x0010 SMB_UNIQUE_FILE_NAME     The server uses long names and does not
 *                                 support short names.  Indicator for
 *                                 clients directory/name-space caching.
 * 0x0020 SMB_EXTENDED_SIGNATURES  The server will use signing key protection.
 *
 * Client-side caching (offline files):
 * ==============================  ==========================
 * 0x0000 SMB_CSC_CACHE_MANUAL_REINT Clients may cache files for offline use
 *                                 but automatic file-by-file reintegration
 *                                 is not allowed.
 * 0x0004 SMB_CSC_CACHE_AUTO_REINT Automatic file-by-file reintegration is
 *                                 allowed.
 * 0x0008 SMB_CSC_CACHE_VDO        File opens do not need to be flowed.
 * 0x000C SMB_CSC_CACHE_NONE       CSC is disabled for this share.
 *
 * Some servers negotiate "DOS LANMAN2.1" dialect or later and still send
 * the "downlevel" (i.e. wordcount==2) response.  Valid AndX following
 * commands are
 *
 * SMB_COM_OPEN              SMB_COM_OPEN_ANDX          SMB_COM_CREATE
 * SMB_COM_CREATE_NEW        SMB_COM_CREATE_DIRECTORY   SMB_COM_DELETE
 * SMB_COM_DELETE_DIRECTORY  SMB_COM_FIND               SMB_COM_COPY
 * SMB_COM_FIND_UNIQUE       SMB_COM_RENAME
 * SMB_COM_CHECK_DIRECTORY   SMB_COM_QUERY_INFORMATION
 * SMB_COM_GET_PRINT_QUEUE   SMB_COM_OPEN_PRINT_FILE
 * SMB_COM_TRANSACTION       SMB_COM_NO_ANDX_CMD
 * SMB_COM_SET_INFORMATION   SMB_COM_NT_RENAME
 *
 * Errors:
 * ERRDOS/ERRnomem
 * ERRDOS/ERRbadpath
 * ERRDOS/ERRinvdevice
 * ERRSRV/ERRaccess
 * ERRSRV/ERRbadpw
 * ERRSRV/ERRinvnetname
 */
smb_sdrc_t
smb_pre_tree_connect_andx(smb_request_t *sr)
{
	smb_arg_tcon_t	*tcon = &sr->sr_tcon;
	uint8_t		*pwbuf = NULL;
	uint16_t	pwlen = 0;
	int		rc;

	rc = smbsr_decode_vwv(sr, "b.www", &sr->andx_com, &sr->andx_off,
	    &tcon->flags, &pwlen);
	if (rc == 0) {
		if (pwlen != 0)
			pwbuf = smb_srm_zalloc(sr, pwlen);

		rc = smbsr_decode_data(sr, "%#cus", sr, pwlen, pwbuf,
		    &tcon->path, &tcon->service);

		tcon->pwdlen = pwlen;
		tcon->password = (char *)pwbuf;
	}

	tcon->optional_support = 0;

	DTRACE_SMB_START(op__TreeConnectX, smb_request_t *, sr);

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

void
smb_post_tree_connect_andx(smb_request_t *sr)
{
	DTRACE_SMB_DONE(op__TreeConnectX, smb_request_t *, sr);
}

smb_sdrc_t
smb_com_tree_connect_andx(smb_request_t *sr)
{
	smb_arg_tcon_t	*tcon = &sr->sr_tcon;
	smb_tree_t	*tree;
	char		*service;
	uint32_t	status;
	int		rc;

	if (tcon->flags & SMB_TCONX_DISCONECT_TID) {
		tree = smb_session_lookup_tree(sr->session, sr->smb_tid);
		if (tree != NULL) {
			smb_tree_disconnect(tree, B_TRUE);
			smb_session_cancel_requests(sr->session, tree, sr);
		}
	}

	status = smb_tree_connect(sr);
	if (status) {
		smb_tcon_puterror(sr, status);
		return (SDRC_ERROR);
	}
	tree = sr->tid_tree;

	switch (tree->t_res_type & STYPE_MASK) {
	case STYPE_IPC:
		service = "IPC";
		break;
	case STYPE_PRINTQ:
		service = "LPT1:";
		break;
	case STYPE_DISKTREE:
	default:
		service = "A:";
	}

	if (sr->session->dialect < NT_LM_0_12) {
		rc = smbsr_encode_result(sr, 2, VAR_BCC, "bb.ww%ss",
		    (char)2,		/* wct */
		    sr->andx_com,
		    VAR_BCC,
		    VAR_BCC,
		    sr,
		    service,
		    tree->t_typename);
	} else if ((tcon->flags & SMB_TCONX_EXTENDED_RESPONSE) == 0) {
		rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%su",
		    (char)3,		/* wct */
		    sr->andx_com,
		    (short)64,
		    tcon->optional_support,
		    VAR_BCC,
		    sr,
		    service,
		    tree->t_typename);

	} else {
		rc = smbsr_encode_result(sr, 7, VAR_BCC, "bb.wwllw%su",
		    (char)7,		/* wct (b) */
		    sr->andx_com,	/* AndXcmd (b) */
		    (short)72,		/* AndXoff (w) */
		    tcon->optional_support,	/* (w) */
		    tree->t_access,		/* (l) */
		    0,		/*    guest_access (l) */
		    VAR_BCC,		/* (w) */
		    sr,			/* (%) */
		    service,		/* (s) */
		    tree->t_typename);	/* (u) */
	}

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

/*
 * SmbTreeDisconnect: Disconnect a tree.
 *
 * Note: SDDF_SUPPRESS_UID is set for this operation, which means the sr
 * uid_user field will not be valid on entry to these functions.  Do not
 * use it until it is set up in smb_com_tree_disconnect() or the system
 * will panic.
 *
 * Note: there are scenarios in which the client does not send a tree
 * disconnect request, for example, when ERRbaduid is returned from
 * SmbReadX after a user has logged off.  Any open files will remain
 * around until the session is destroyed.
 *
 * Client Request                     Description
 * ================================== =================================
 *
 * UCHAR WordCount;                   Count of parameter words = 0
 * USHORT ByteCount;                  Count of data bytes = 0
 *
 * The resource sharing connection identified by Tid in the SMB header is
 * logically disconnected from the server. Tid is invalidated; it will not
 * be recognized if used by the client for subsequent requests. All locks,
 * open files, etc. created on behalf of Tid are released.
 *
 * Server Response                    Description
 * ================================== =================================
 *
 * UCHAR WordCount;                   Count of parameter words = 0
 * USHORT ByteCount;                  Count of data bytes = 0
 *
 * Errors:
 * ERRSRV/ERRinvnid
 * ERRSRV/ERRbaduid
 */
smb_sdrc_t
smb_pre_tree_disconnect(smb_request_t *sr)
{
	sr->uid_user = smb_session_lookup_uid(sr->session, sr->smb_uid);
	sr->tid_tree = smb_session_lookup_tree(sr->session, sr->smb_tid);

	DTRACE_SMB_START(op__TreeDisconnect, smb_request_t *, sr);
	return (SDRC_SUCCESS);
}

void
smb_post_tree_disconnect(smb_request_t *sr)
{
	DTRACE_SMB_DONE(op__TreeDisconnect, smb_request_t *, sr);
}

/*
 * SmbTreeDisconnect requires a valid UID as well as a valid TID.  Some
 * clients logoff a user and then try to disconnect the trees connected
 * by the user who has just been logged off, which would normally fail
 * in the dispatch code with ERRbaduid but, unfortunately, ERRbaduid
 * causes a problem for some of those clients.  Windows returns ERRinvnid.
 *
 * To prevent ERRbaduid being returned, the UID and TID are looked up here
 * rather than prior to dispatching SmbTreeDisconnect requests.  If either
 * the UID or the TID is invalid, ERRinvnid is returned.
 */
smb_sdrc_t
smb_com_tree_disconnect(smb_request_t *sr)
{
	if (sr->uid_user == NULL || sr->tid_tree == NULL) {
		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRinvnid);
		return (SDRC_ERROR);
	}

	sr->user_cr = smb_user_getcred(sr->uid_user);

	smb_tree_disconnect(sr->tid_tree, B_TRUE);
	smb_session_cancel_requests(sr->session, sr->tid_tree, sr);

	if (smbsr_encode_empty_result(sr))
		return (SDRC_ERROR);

	return (SDRC_SUCCESS);
}