smbrdr_read_andx.c revision 12508:edb7861a1533
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26/*
27 * SMB ReadX functions.
28 */
29
30#include <strings.h>
31
32#include <smbsrv/libsmbrdr.h>
33#include <smbsrv/netbios.h>
34#include <smbrdr.h>
35
36#define	SMBRDR_READX_RSP_OVERHEAD \
37	(NETBIOS_HDR_SZ + SMB_HEADER_LEN + sizeof (smb_read_andx_rsp_t))
38#define	SMBRDR_READX_RSP_DATA_MAXLEN \
39	(SMBRDR_REQ_BUFSZ - SMBRDR_READX_RSP_OVERHEAD)
40
41static int smbrdr_decode_readx_rsp(smb_msgbuf_t *, char *, unsigned,
42    smb_read_andx_rsp_t *);
43
44/*
45 * smbrdr_readx
46 *
47 * Send SMB_COM_READ_ANDX request.
48 */
49int
50smbrdr_readx(int fid, char *in_buf, int in_len)
51{
52	struct sdb_netuse *netuse;
53	struct sdb_ofile *ofile;
54	smb_read_andx_rsp_t rsp;
55	smbrdr_handle_t srh;
56	smb_msgbuf_t *mb;
57	DWORD status;
58	int rc, max_return;
59
60	if ((ofile = smbrdr_ofile_get(fid)) == NULL)
61		return (-1);
62
63	netuse = ofile->netuse;
64
65	status = smbrdr_request_init(&srh, SMB_COM_READ_ANDX,
66	    netuse->session, &netuse->session->logon, netuse);
67
68	if (status != NT_STATUS_SUCCESS) {
69		smb_log(smbrdr_log_hdl, LOG_DEBUG, "smbrdr_readx: %s",
70		    xlate_nt_status(status));
71		smbrdr_ofile_put(ofile);
72		return (-1);
73	}
74
75	mb = &(srh.srh_mbuf);
76
77	max_return = (in_len > SMBRDR_READX_RSP_DATA_MAXLEN) ?
78	    SMBRDR_READX_RSP_DATA_MAXLEN : in_len;
79
80	rc = smb_msgbuf_encode(mb, "bbbwwlwwlwlw",
81	    12,		/* Count of parameter words */
82	    0xFF,	/* Secondary (X) command; 0xFF = none */
83	    0,		/* Reserved (must be 0) */
84	    0, 		/* Offset to next command WordCount */
85	    ofile->fid,	/* File handle */
86	    0,		/* Offset in file to begin read */
87	    max_return,	/* Max number of bytes to return */
88		/* Reserved for obsolescent requests [0 = non-blocking read] */
89	    max_return,
90		/*
91		 * High 16 bits of MaxCount if CAP_LARGE_READX;
92		 * else MUST BE ZERO
93		 */
94	    0,
95	    max_return,	/* Reserved for obsolescent requests */
96	    /* Upper 32 bits of offset (only if WordCount is 12) */
97	    0,
98	    0);		/* Count of data bytes = 0 */
99
100	if (rc < 0) {
101		smb_log(smbrdr_log_hdl, LOG_DEBUG, "smbrdr_readx: prep failed");
102		smbrdr_handle_free(&srh);
103		smbrdr_ofile_put(ofile);
104		return (rc);
105	}
106
107	smbrdr_lock_transport();
108
109	status = smbrdr_send(&srh);
110	if (status != NT_STATUS_SUCCESS) {
111		smbrdr_unlock_transport();
112		smbrdr_handle_free(&srh);
113		smbrdr_ofile_put(ofile);
114		smb_log(smbrdr_log_hdl, LOG_DEBUG, "smbrdr_readx: send failed");
115		return (-1);
116	}
117
118	status = smbrdr_rcv(&srh, 1);
119
120	if (status != NT_STATUS_SUCCESS) {
121		smb_log(smbrdr_log_hdl, LOG_DEBUG,
122		    "smbrdr_readx: nb_rcv failed");
123		smbrdr_unlock_transport();
124		smbrdr_handle_free(&srh);
125		smbrdr_ofile_put(ofile);
126		return (-1);
127	}
128
129	rc = smbrdr_decode_readx_rsp(mb, in_buf, in_len, &rsp);
130
131	if (rc < 0) {
132		smb_log(smbrdr_log_hdl, LOG_DEBUG,
133		    "smbrdr_readx: decode failed");
134		smbrdr_unlock_transport();
135		smbrdr_handle_free(&srh);
136		smbrdr_ofile_put(ofile);
137		return (-1);
138	}
139
140	smbrdr_unlock_transport();
141	smbrdr_handle_free(&srh);
142	smbrdr_ofile_put(ofile);
143
144	return ((rc < 0) ? rc : rsp.DataLength);
145}
146
147/*
148 * smbrdr_decode_readx_rsp
149 *
150 * Decode the response from the SMB_COM_READ_ANDX request. The payload
151 * of the response is appended to the end of SmbTransact response data
152 * in the RPC receive buffer.
153 *
154 * Return -1 on error, 0 upon success.
155 */
156static int
157smbrdr_decode_readx_rsp(smb_msgbuf_t *mb,
158			char *in,
159			unsigned in_len,
160			smb_read_andx_rsp_t *rsp)
161{
162	int rc;
163
164	rc = smb_msgbuf_decode(mb, "bbbwwwwwwlwwww",
165	    &rsp->WordCount,
166	    &rsp->AndXCmd,
167	    &rsp->AndXReserved,
168	    &rsp->AndXOffset,
169	    &rsp->Remaining,
170	    &rsp->DataCompactionMode,
171	    &rsp->Reserved,
172	    &rsp->DataLength,
173	    &rsp->DataOffset,
174	    &rsp->DataLengthHigh,
175	    &rsp->Reserved2[0],
176	    &rsp->Reserved2[1],
177	    &rsp->Reserved2[2],
178	    &rsp->ByteCount);
179
180	if (rc <= 0)
181		return (-1);
182
183	if (rsp->DataLength > in_len)
184		return (-1);
185
186	bcopy(mb->base + rsp->DataOffset, in, rsp->DataLength);
187
188	return (0);
189}
190