smb_dispatch.c revision b24e356b384ccc80805e7150979de2373d44347c
/*
* 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
* 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 2014 Nexenta Systems, Inc. All rights reserved.
*/
/*
* SMB requests.
*
* Request
* Header
* Magic 0xFF 'S' 'M' 'B'
* smb_com a byte, the "first" command
* Error a 4-byte union, ignored in a request
* smb_flg a one byte set of eight flags
* smb_flg2 a two byte set of 16 flags
* . twelve reserved bytes, have a role
* in connectionless transports (IPX, UDP?)
* smb_tid a 16-bit tree ID, a mount point sorta,
* 0xFFFF is this command does not have
* or require a tree context
* smb_pid a 16-bit process ID
* smb_uid a 16-bit user ID, specific to this "session"
* and mapped to a system (bona-fide) UID
* smb_mid a 16-bit multiplex ID, used to differentiate
* multiple simultaneous requests from the same
* process (pid) (ref RPC "xid")
*
* Chained (AndX) commands (0 or more)
* smb_wct a byte, number of 16-bit words containing
* command parameters, min 2 for chained command
* andx_com a byte, the "next" command, 0xFF for none
* . an unused byte
* andx_off a 16-bit offset, byte displacement from &Magic
* to the smb_wct field of the "next" command,
* ignore if andx_com is 0xFF, s/b 0 if no next
* smb_vwv[] 0 or more 16-bit (sorta) parameters for
* "this" command (i.e. smb_com if this is the
* first parameters, or the andx_com of the just
* previous block.
* smb_bcc a 16-bit count of smb_data[] bytes
* smb_data[] 0 or more bytes, format specific to commands
* padding[] Optional padding
*
* Last command
* smb_wct a byte, number of 16-bit words containing
* command parameters, min 0 for chained command
* smb_vwv[] 0 or more 16-bit (sorta) parameters for
* "this" command (i.e. smb_com if this is the
* first parameters, or the andx_com of the just
* previous block.
* smb_bcc a 16-bit count of smb_data[] bytes
* smb_data[] 0 or more bytes, format specific to commands
*
* Reply
* Header
* Magic 0xFF 'S' 'M' 'B'
* smb_com a byte, the "first" command, corresponds
* to request
* Error a 4-byte union, coding depends on dialect in use
* for "DOS" errors
* a byte for error class
* an unused byte
* a 16-bit word for error code
* for "NT" errors
* a 32-bit error code which
* is a packed class and specifier
* for "OS/2" errors
* I don't know
* The error information is specific to the
* last command in the reply chain.
* smb_flg a one byte set of eight flags, 0x80 bit set
* indicating this message is a reply
* smb_flg2 a two byte set of 16 flags
* . twelve reserved bytes, have a role
* in connectionless transports (IPX, UDP?)
* smb_tid a 16-bit tree ID, a mount point sorta,
* should be the same as the request
* smb_pid a 16-bit process ID, MUST BE the same as request
* smb_uid a 16-bit user ID, specific to this "session"
* and mapped to a system (bona-fide) UID,
* should be the same as request
* smb_mid a 16-bit multiplex ID, used to differentiate
* multiple simultaneous requests from the same
* process (pid) (ref RPC "xid"), MUST BE the
* same as request
* padding[] Optional padding
*
* Chained (AndX) commands (0 or more)
* smb_wct a byte, number of 16-bit words containing
* command parameters, min 2 for chained command,
* andx_com a byte, the "next" command, 0xFF for none,
* corresponds to request, if this is the chained
* command that had an error set to 0xFF
* . an unused byte
* andx_off a 16-bit offset, byte displacement from &Magic
* to the smb_wct field of the "next" command,
* ignore if andx_com is 0xFF, s/b 0 if no next
* smb_vwv[] 0 or more 16-bit (sorta) parameters for
* "this" command (i.e. smb_com if this is the
* first parameters, or the andx_com of the just
* previous block. Empty if an error.
* smb_bcc a 16-bit count of smb_data[] bytes
* smb_data[] 0 or more bytes, format specific to commands
* empty if an error.
*
* Last command
* smb_wct a byte, number of 16-bit words containing
* command parameters, min 0 for chained command
* smb_vwv[] 0 or more 16-bit (sorta) parameters for
* "this" command (i.e. smb_com if this is the
* first parameters, or the andx_com of the just
* previous block, empty if an error.
* smb_bcc a 16-bit count of smb_data[] bytes
* smb_data[] 0 or more bytes, format specific to commands,
* empty if an error.
*/
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_kstat.h>
static int is_andx_com(unsigned char);
static int smbsr_check_result(struct smb_request *, int, int);
static const smb_disp_entry_t const
0x00, PC_NETWORK_PROGRAM_1_0 },
0x01, PC_NETWORK_PROGRAM_1_0 },
0x02, PC_NETWORK_PROGRAM_1_0 },
0x03, PC_NETWORK_PROGRAM_1_0 },
0x04, PC_NETWORK_PROGRAM_1_0 },
0x05, PC_NETWORK_PROGRAM_1_0 },
0x06, PC_NETWORK_PROGRAM_1_0 },
0x07, PC_NETWORK_PROGRAM_1_0 },
0x08, PC_NETWORK_PROGRAM_1_0 },
0x09, PC_NETWORK_PROGRAM_1_0 },
0x0A, PC_NETWORK_PROGRAM_1_0 },
0x0B, PC_NETWORK_PROGRAM_1_0 },
0x0C, PC_NETWORK_PROGRAM_1_0 },
0x0D, PC_NETWORK_PROGRAM_1_0 },
0x0E, PC_NETWORK_PROGRAM_1_0 },
0x0F, PC_NETWORK_PROGRAM_1_0 },
0x10, PC_NETWORK_PROGRAM_1_0 },
0x11, PC_NETWORK_PROGRAM_1_0,
0x12, PC_NETWORK_PROGRAM_1_0 },
0x13, LANMAN1_0 },
0x14, LANMAN1_0 },
0x22, LANMAN1_0 },
{ "SmbQueryInformation2",
0x23, LANMAN1_0 },
0x24, LANMAN1_0 },
0x25, LANMAN1_0 },
{ "SmbTransactionSecondary",
0x26, LANMAN1_0 },
0x27, LANMAN1_0 },
0x2C, LANMAN1_0 },
0x2D, LANMAN1_0 },
0x2E, LANMAN1_0 },
0x2F, LANMAN1_0 },
{ "SmbCloseAndTreeDisconnect",
0x31, LANMAN1_0 },
0x32, LM1_2X002 },
{ "SmbTransaction2Secondary",
0x33, LM1_2X002 },
0x34, LM1_2X002 },
0x71, PC_NETWORK_PROGRAM_1_0,
0x72, PC_NETWORK_PROGRAM_1_0,
{ "SmbQueryInformationDisk",
0x80, PC_NETWORK_PROGRAM_1_0, 0 },
0x81, PC_NETWORK_PROGRAM_1_0, 0 },
0x82, LANMAN1_0, 0 },
0x83, LANMAN1_0, 0 },
0x84, LANMAN1_0, 0 },
0xA0, NT_LM_0_12, 0 },
{ "SmbNtTransactSecondary",
0xA1, NT_LM_0_12, 0 },
0xA2, NT_LM_0_12, 0 },
0xA4, NT_LM_0_12, 0 },
0xA5, NT_LM_0_12, 0 },
0xC0, PC_NETWORK_PROGRAM_1_0, 0 },
0xC1, PC_NETWORK_PROGRAM_1_0, 0 },
0xC2, PC_NETWORK_PROGRAM_1_0, 0 },
0xC3, PC_NETWORK_PROGRAM_1_0, 0 },
};
/*
* smbsr_cleanup
*
* the reference count for that resource has been incremented.
* This function decrements the reference count and close
* the resource if it's needed.
*/
void
{
}
/*
* Mark this request so we know that we've already cleaned it up.
* A request should only get cleaned up once so multiple calls to
* smbsr_cleanup for the same request indicate a bug.
*/
}
/*
* smb_dispatch_request
*
* Returns:
*
* B_TRUE The caller must free the smb request passed in.
* B_FALSE The caller must not access the smb request passed in. It has
* been kept in an internal queue and may have already been freed.
*/
{
const smb_disp_entry_t *sdd;
/* temporary until we identify a user */
/* If this connection is shutting down just kill request */
&sr->smb_pid_high,
disconnect = B_TRUE;
goto drop_connection;
}
/*
* The reply "header" is filled in now even though it will,
* most likely, be rewritten under reply_ready below. We
* could reserve the space but this is convenient in case
* the dialect dispatcher has to send a special reply (like
* TRANSACT).
*
* Ensure that the 32-bit error code flag is turned off.
* Clients seem to set it in transact requests and they may
* get confused if we return success or a 16-bit SMB code.
*/
smb_sign_check_request(sr) != 0) {
disconnect = B_TRUE;
goto report_error;
}
}
disconnect = B_TRUE;
goto report_error;
}
disconnect = B_TRUE;
goto report_error;
}
/*
* Ignore smb_bcc if CAP_LARGE_READX/CAP_LARGE_WRITEX
*/
/* Allow > BCC */
/* BCC is bogus. Will fail later. */
} else {
/* ordinary case */
}
disconnect = B_TRUE;
goto report_error;
}
/* Store pointers for later */
/* Peek ahead and don't disturb vwv */
disconnect = B_TRUE;
goto report_error;
}
} else {
}
case SMB_REQ_STATE_SUBMITTED:
case SMB_REQ_STATE_CLEANED_UP:
break;
case SMB_REQ_STATE_CANCELED:
break;
default:
ASSERT(0);
break;
}
/*
* Setup UID and TID information (if required). Both functions
* will set the sr credentials. In domain mode, the user and
* tree credentials should be the same. In share mode, the
* tree credentials (defined in the share definition) should
* override the user credentials.
*/
goto report_error;
}
}
goto report_error;
}
}
/*
* If the command is not a read raw request we can set the
* state of the session back to SMB_SESSION_STATE_NEGOTIATED
* (if the current state is SMB_SESSION_STATE_OPLOCK_BREAKING).
* Otherwise we let the read raw handler to deal with it.
*/
}
if (sdrc != SDRC_SR_KEPT) {
}
switch (sdrc) {
case SDRC_SUCCESS:
break;
case SDRC_DROP_VC:
disconnect = B_TRUE;
goto drop_connection;
case SDRC_NO_REPLY:
return (B_TRUE);
case SDRC_SR_KEPT:
return (B_FALSE);
case SDRC_ERROR:
goto report_error;
case SDRC_NOT_IMPLEMENTED:
default:
goto report_error;
}
/*
* If there's no AndX command, we're done.
*/
goto reply_ready;
/*
* Otherwise, we have to back-patch the AndXCommand and AndXOffset
* and continue processing.
*/
goto andx_more;
if (disconnect) {
break;
default:
break;
}
}
return (B_TRUE);
}
int
{
}
int
{
return (-1);
return (-1);
return (0);
}
static int
{
int total_bytes;
struct mbuf *m;
total_bytes = 0;
while (m != 0) {
total_bytes += m->m_len;
m = m->m_next;
}
return (-1);
return (-1);
return (-1);
/* reply wct & vwv seem ok, consider data now */
return (-1);
return (-1);
} else {
}
} else {
return (-1);
}
if (offset != total_bytes)
return (-1);
return (0);
}
int
{
int rc;
if (rc)
return (rc);
}
int
{
int rc;
if (rc)
return (rc);
}
{
}
void
{
else
}
/*
* Map errno values to SMB and NT status values.
* Note: ESRCH is a special case to handle a streams lookup failure.
*/
static const struct {
int errnum;
int errcls;
int errcode;
} const smb_errno_map[] = {
/*
* It's not clear why smb_read_common effectively returns
* ERRnoaccess if a range lock prevents access and smb_write_common
* effectively returns ERRaccess. This table entry is used by
* smb_read_common and preserves the behavior that was there before.
*/
};
void
{
int i;
for (i = 0; i < sizeof (smb_errno_map)/sizeof (smb_errno_map[0]); ++i) {
return;
}
}
}
void
{
}
/*
* Report a request processing status (error or warning).
*/
void
{
}
/*
* Setup a request processing error. This function can be used to
* report 32-bit status codes or DOS errors. Set the status code
* to 0 (NT_STATUS_SUCCESS) to explicitly report a DOS error,
* regardless of the client capabilities.
*
* If status is non-zero and the client supports 32-bit status
* codes, report the status. Otherwise, report the DOS error.
*/
void
{
if (status == 0)
}
} else {
} else {
}
}
}
smb_xa_t *
{
}
void
{
(void) smb_ofile_release(of);
}
void
{
}
static int
is_andx_com(unsigned char com)
{
switch (com) {
case SMB_COM_LOCKING_ANDX:
case SMB_COM_OPEN_ANDX:
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
case SMB_COM_LOGOFF_ANDX:
case SMB_COM_NT_CREATE_ANDX:
return (1);
}
return (0);
}
/*
* Invalid command stubs.
*
* SmbWriteComplete is sent to acknowledge completion of raw write requests.
* We never send raw write commands to other servers so, if we receive
* SmbWriteComplete, we treat it as an error.
*
* protocol is not supported because we support only connection oriented
* transports and NT supports mpx only over connectionless transports.
*/
{
return (SDRC_SUCCESS);
}
void
{
}
{
case SMB_COM_WRITE_COMPLETE:
sdrc = SDRC_ERROR;
break;
default:
break;
}
return (sdrc);
}
/*
* smb_dispatch_stats_init
*
* Initializes dispatch statistics.
*/
void
{
int ks_ndata;
int i;
for (i = 0; i < SMB_COM_NUM; i++, ksr++) {
}
/* Legacy Statistics */
for (i = 0, ks_ndata = 0; i < SMB_COM_NUM; i++) {
ks_ndata++;
}
}
/*
* smb_dispatch_stats_fini
*
* Frees and destroyes the resources used for statistics.
*/
void
{
int i;
for (i = 0; i < SMB_COM_NUM; i++)
}
void
{
int i;
int last;
ksr->kr_a_stddev =
ksr->kr_d_stddev =
}
}
}