smbrdr_read_andx.c revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* SMB ReadX functions to support MLRPC.
*/
#include <syslog.h>
#include <strings.h>
#include <smbsrv/libsmbrdr.h>
#include <smbsrv/netbios.h>
#include <smbsrv/ntstatus.h>
#include <smbrdr.h>
#define SMBRDR_READX_RSP_OVERHEAD \
(NETBIOS_HDR_SZ + SMB_HEADER_LEN + sizeof (smb_read_andx_rsp_t))
#define SMBRDR_READX_RSP_DATA_MAXLEN \
(SMBRDR_REQ_BUFSZ - SMBRDR_READX_RSP_OVERHEAD)
static int smbrdr_decode_readx_rsp(smb_msgbuf_t *, char *, unsigned,
smb_read_andx_rsp_t *);
static void smbrdr_dump_readx_rsp(smb_read_andx_rsp_t *);
/*
* smbrdr_rpc_readx
*
* Send SMB_COM_READ_ANDX request.
*/
int
smbrdr_rpc_readx(int fid, char *in_buf, int in_len)
{
struct sdb_netuse *netuse;
struct sdb_ofile *ofile;
smb_read_andx_rsp_t rsp;
smbrdr_handle_t srh;
smb_msgbuf_t *mb;
DWORD status;
int rc, max_return;
if ((ofile = smbrdr_ofile_get(fid)) == 0)
return (-1);
netuse = ofile->netuse;
status = smbrdr_request_init(&srh, SMB_COM_READ_ANDX,
netuse->session, &netuse->session->logon, netuse);
if (status != NT_STATUS_SUCCESS) {
syslog(LOG_ERR, "SmbrdrReadAndx: %s", xlate_nt_status(status));
smbrdr_ofile_put(ofile);
return (-1);
}
mb = &(srh.srh_mbuf);
max_return = (in_len > SMBRDR_READX_RSP_DATA_MAXLEN) ?
SMBRDR_READX_RSP_DATA_MAXLEN : in_len;
rc = smb_msgbuf_encode(mb, "bbbwwlwwlwlw",
12, /* Count of parameter words */
0xFF, /* Secondary (X) command; 0xFF = none */
0, /* Reserved (must be 0) */
0, /* Offset to next command WordCount */
ofile->fid, /* File handle */
0, /* Offset in file to begin read */
max_return, /* Max number of bytes to return */
/* Reserved for obsolescent requests [0 = non-blocking read] */
max_return,
/*
* High 16 bits of MaxCount if CAP_LARGE_READX;
* else MUST BE ZERO
*/
0,
max_return, /* Reserved for obsolescent requests */
/* Upper 32 bits of offset (only if WordCount is 12) */
0,
0); /* Count of data bytes = 0 */
if (rc < 0) {
syslog(LOG_ERR, "SmbrdrReadAndx: smbrdr_prep_readx_req failed");
smbrdr_handle_free(&srh);
smbrdr_ofile_put(ofile);
return (rc);
}
smbrdr_lock_transport();
status = smbrdr_send(&srh);
if (status != NT_STATUS_SUCCESS) {
smbrdr_unlock_transport();
smbrdr_handle_free(&srh);
smbrdr_ofile_put(ofile);
syslog(LOG_ERR, "SmbrdrReadAndx: send failed");
return (-1);
}
status = smbrdr_rcv(&srh, 1);
if (status != NT_STATUS_SUCCESS) {
syslog(LOG_ERR, "SmbrdrReadAndx: nb_rcv failed");
smbrdr_unlock_transport();
smbrdr_handle_free(&srh);
smbrdr_ofile_put(ofile);
return (-1);
}
rc = smbrdr_decode_readx_rsp(mb, in_buf, in_len, &rsp);
if (rc < 0) {
syslog(LOG_ERR, "SmbrdrReadAndx: read decode failure!");
smbrdr_unlock_transport();
smbrdr_handle_free(&srh);
smbrdr_ofile_put(ofile);
return (-1);
}
smbrdr_unlock_transport();
smbrdr_handle_free(&srh);
smbrdr_ofile_put(ofile);
return ((rc < 0) ? rc : rsp.DataLength);
}
static void
smbrdr_dump_readx_rsp(smb_read_andx_rsp_t *rsp)
{
syslog(LOG_DEBUG, "[SmbReadX Rsp] WordCount:%x,AndXCmd:%x,"
" AndXReserved:%x, AndXOffset:%d",
rsp->WordCount, rsp->AndXCmd, rsp->AndXReserved, rsp->AndXOffset);
syslog(LOG_DEBUG, "[SmbReadX Rsp] Remaining:%d, Mode:%d, Reserved:%x, "
"DataLen:%d, DataOffset:%d, ByteCount: %d",
rsp->Remaining, rsp->DataCompactionMode, rsp->Reserved,
rsp->DataLength, rsp->DataOffset, rsp->ByteCount);
}
/*
* smbrdr_decode_readx_rsp
*
* Decode the response from the SMB_COM_READ_ANDX request. The payload
* of the response is appended to the end of SmbTransact response data
* in the MLRPC receive buffer.
*
* Return -1 on error, 0 upon success.
*/
static int
smbrdr_decode_readx_rsp(smb_msgbuf_t *mb,
char *in,
unsigned in_len,
smb_read_andx_rsp_t *rsp)
{
int rc;
rc = smb_msgbuf_decode(mb, "bbbwwwwwwlwwww",
&rsp->WordCount,
&rsp->AndXCmd,
&rsp->AndXReserved,
&rsp->AndXOffset,
&rsp->Remaining,
&rsp->DataCompactionMode,
&rsp->Reserved,
&rsp->DataLength,
&rsp->DataOffset,
&rsp->DataLengthHigh,
&rsp->Reserved2[0],
&rsp->Reserved2[1],
&rsp->Reserved2[2],
&rsp->ByteCount);
if (rc <= 0)
return (-1);
smbrdr_dump_readx_rsp(rsp);
/* it should never happen, but check anyway */
if (rsp->DataLength > in_len)
return (-1);
bcopy(mb->base + rsp->DataOffset, in, rsp->DataLength);
return (0);
}