2 Unix SMB/CIFS implementation.
4 Copyright (C) Gregor Beck 2013
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "system/network.h"
22 #include "lib/util/tevent_ntstatus.h"
23 #include "smb_common.h"
24 #include "smbXcli_base.h"
26 struct smb1cli_readx_state
{
34 static void smb1cli_readx_done(struct tevent_req
*subreq
);
37 * Send an asynchrounus SMB_COM_READ_ANDX request.
38 * <a href="http://msdn.microsoft.com/en-us/library/ee441839.aspx">MS-CIFS 2.2.4.42.1</a>,
39 * <a href="http://msdn.microsoft.com/en-us/library/ff470250.aspx">MS-SMB 2.2.4.2.1</a>
40 * @see smb1cli_readx_recv()
41 * @todo fix API (min/max size, timeout)
43 * @param[in] mem_ctx The memory context for the result.
44 * @param[in] ev The event context to work on.
45 * @param[in] conn The smb connection.
46 * @param[in] timeout_msec If positiv a timeout for the request.
47 * @param[in] pid The process identifier
48 * @param[in] tcon The smb tree connect.
49 * @param[in] session The smb session.
50 * @param[in] fnum The file id of the file the data should be read from.
51 * @param[in] offset The offset in bytes from the begin of file where to start reading.
52 * @param[in] size The number of bytes to read.
54 * @return a tevent_req or NULL
56 struct tevent_req
*smb1cli_readx_send(TALLOC_CTX
*mem_ctx
,
57 struct tevent_context
*ev
,
58 struct smbXcli_conn
*conn
,
59 uint32_t timeout_msec
,
61 struct smbXcli_tcon
*tcon
,
62 struct smbXcli_session
*session
,
68 struct tevent_req
*req
, *subreq
;
69 struct smb1cli_readx_state
*state
;
72 req
= tevent_req_create(mem_ctx
, &state
, struct smb1cli_readx_state
);
78 SCVAL(state
->vwv
+ 0, 0, 0xFF);
79 SCVAL(state
->vwv
+ 0, 1, 0);
80 SSVAL(state
->vwv
+ 1, 0, 0);
81 SSVAL(state
->vwv
+ 2, 0, fnum
);
82 SIVAL(state
->vwv
+ 3, 0, offset
);
83 SSVAL(state
->vwv
+ 5, 0, size
);
84 SSVAL(state
->vwv
+ 6, 0, size
);
85 SSVAL(state
->vwv
+ 7, 0, (size
>> 16));
86 SSVAL(state
->vwv
+ 8, 0, 0);
87 SSVAL(state
->vwv
+ 9, 0, 0);
89 if (smb1cli_conn_capabilities(conn
) & CAP_LARGE_FILES
) {
90 SIVAL(state
->vwv
+ 10, 0,
91 (((uint64_t)offset
)>>32) & 0xffffffff);
94 if ((((uint64_t)offset
) & 0xffffffff00000000LL
) != 0) {
95 DEBUG(10, ("smb1cli_readx_send got large offset where "
96 "the server does not support it\n"));
97 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
98 return tevent_req_post(req
, ev
);
102 subreq
= smb1cli_req_create(state
, ev
, conn
, SMBreadX
,
105 timeout_msec
, pid
, tcon
, session
,
108 if (tevent_req_nomem(subreq
, req
)) {
109 return tevent_req_post(req
, ev
);
111 tevent_req_set_callback(subreq
, smb1cli_readx_done
, req
);
113 status
= smb1cli_req_chain_submit(&subreq
, 1);
114 if (tevent_req_nterror(req
, status
)) {
115 return tevent_req_post(req
, ev
);
121 static void smb1cli_readx_done(struct tevent_req
*subreq
)
123 struct tevent_req
*req
= tevent_req_callback_data(
124 subreq
, struct tevent_req
);
125 struct smb1cli_readx_state
*state
= tevent_req_data(
126 req
, struct smb1cli_readx_state
);
127 struct iovec
*recv_iov
= NULL
;
132 uint16_t data_offset
;
133 uint32_t bytes_offset
;
135 static const struct smb1cli_req_expected_response expected
[] = {
137 .status
= NT_STATUS_OK
,
141 .status
= STATUS_BUFFER_OVERFLOW
,
146 status
= smb1cli_req_recv(subreq
, state
,
151 NULL
, /* pvwv_offset */
156 expected
, ARRAY_SIZE(expected
));
158 if (NT_STATUS_EQUAL(status
, STATUS_BUFFER_OVERFLOW
)) {
161 if (tevent_req_nterror(req
, status
)) {
166 /* size is the number of bytes the server returned.
168 state
->received
= SVAL(vwv
+ 5, 0);
169 state
->received
|= (((unsigned int)SVAL(vwv
+ 7, 0)) << 16);
171 if (state
->received
> state
->size
) {
172 DEBUG(5,("server returned more than we wanted!\n"));
173 tevent_req_nterror(req
, NT_STATUS_UNEXPECTED_IO_ERROR
);
178 * bcc field must be valid for small reads, for large reads the 16-bit
179 * bcc field can't be correct.
181 if ((state
->received
< 0xffff) && (state
->received
> num_bytes
)) {
182 DEBUG(5, ("server announced more bytes than sent\n"));
183 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
187 data_offset
= SVAL(vwv
+6, 0);
188 if (data_offset
< bytes_offset
) {
189 DEBUG(5, ("server returned invalid read&x data offset\n"));
190 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
193 if (smb_buffer_oob(num_bytes
, data_offset
- bytes_offset
, state
->received
)) {
194 DEBUG(5, ("server returned invalid read&x data offset\n"));
195 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
199 state
->buf
= bytes
+ (data_offset
- bytes_offset
);
201 state
->out_valid
= true;
203 if (tevent_req_nterror(req
, status
)) {
207 tevent_req_done(req
);
211 * Receive the response to an asynchronous SMB_COM_READ_ANDX request.
212 * <a href="http://msdn.microsoft.com/en-us/library/ee441872.aspx">MS-CIFS 2.2.4.42.2</a>,
213 * <a href="http://msdn.microsoft.com/en-us/library/ff470017.aspx">MS-SMB 2.2.4.2.2</a>
215 * @warning rcvbuf is talloced from the request, so better make sure that you
216 * copy it away before you talloc_free(req). rcvbuf is NOT a talloc_ctx of its
217 * own, so do not talloc_move it!
219 * @param[in] req A tevent request created with smb1cli_readx_send()
220 * @param[out] received The number of bytes received.
221 * @param[out] rcvbuf Pointer to the bytes received.
223 * @return NT_STATUS_OK or STATUS_BUFFER_OVERFLOW on succsess.
225 NTSTATUS
smb1cli_readx_recv(struct tevent_req
*req
,
229 struct smb1cli_readx_state
*state
= tevent_req_data(
230 req
, struct smb1cli_readx_state
);
231 NTSTATUS status
= NT_STATUS_OK
;
233 if (tevent_req_is_nterror(req
, &status
) && !state
->out_valid
) {
238 *received
= state
->received
;
239 *rcvbuf
= state
->buf
;