torture: NULL out after talloc_free
[Samba.git] / libcli / smb / smb1cli_read.c
blobab250abf143c9b94b54428fa3cab39b71aa3f897
1 /*
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/>.
20 #include "includes.h"
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 {
27 uint32_t size;
28 uint16_t vwv[12];
29 NTSTATUS status;
30 uint32_t received;
31 uint8_t *buf;
34 static void smb1cli_readx_done(struct tevent_req *subreq);
36 /**
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,
60 uint32_t pid,
61 struct smbXcli_tcon *tcon,
62 struct smbXcli_session *session,
63 uint16_t fnum,
64 uint64_t offset,
65 uint32_t size)
67 NTSTATUS status;
68 struct tevent_req *req, *subreq;
69 struct smb1cli_readx_state *state;
70 uint8_t wct = 10;
72 req = tevent_req_create(mem_ctx, &state, struct smb1cli_readx_state);
73 if (req == NULL) {
74 return NULL;
76 state->size = size;
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);
92 wct = 12;
93 } else {
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,
103 0, 0, /* *_flags */
104 0, 0, /* *_flags2 */
105 timeout_msec, pid, tcon, session,
106 wct, state->vwv,
107 0, NULL);
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);
118 return req;
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;
128 uint8_t wct;
129 uint16_t *vwv;
130 uint32_t num_bytes;
131 uint8_t *bytes;
132 uint16_t data_offset;
133 uint32_t bytes_offset;
134 static const struct smb1cli_req_expected_response expected[] = {
136 .status = NT_STATUS_OK,
137 .wct = 0x0C
141 state->status = smb1cli_req_recv(subreq, state,
142 &recv_iov,
143 NULL, /* phdr */
144 &wct,
145 &vwv,
146 NULL, /* pvwv_offset */
147 &num_bytes,
148 &bytes,
149 &bytes_offset,
150 NULL, /* inbuf */
151 expected, ARRAY_SIZE(expected));
152 TALLOC_FREE(subreq);
153 if (tevent_req_nterror(req, state->status)) {
154 return;
157 /* size is the number of bytes the server returned.
158 * Might be zero. */
159 state->received = SVAL(vwv + 5, 0);
160 state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16);
162 if (state->received > state->size) {
163 DEBUG(5,("server returned more than we wanted!\n"));
164 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
165 return;
169 * bcc field must be valid for small reads, for large reads the 16-bit
170 * bcc field can't be correct.
172 if ((state->received < 0xffff) && (state->received > num_bytes)) {
173 DEBUG(5, ("server announced more bytes than sent\n"));
174 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
175 return;
178 data_offset = SVAL(vwv+6, 0);
179 if (data_offset < bytes_offset) {
180 DEBUG(5, ("server returned invalid read&x data offset\n"));
181 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
182 return;
184 if (smb_buffer_oob(num_bytes, data_offset - bytes_offset, state->received)) {
185 DEBUG(5, ("server returned invalid read&x data offset\n"));
186 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
187 return;
190 state->buf = bytes + (data_offset - bytes_offset);
192 tevent_req_done(req);
196 * Receive the response to an asynchronous SMB_COM_READ_ANDX request.
197 * <a href="http://msdn.microsoft.com/en-us/library/ee441872.aspx">MS-CIFS 2.2.4.42.2</a>,
198 * <a href="http://msdn.microsoft.com/en-us/library/ff470017.aspx">MS-SMB 2.2.4.2.2</a>
200 * @warning rcvbuf is talloced from the request, so better make sure that you
201 * copy it away before you talloc_free(req). rcvbuf is NOT a talloc_ctx of its
202 * own, so do not talloc_move it!
204 * @param[in] req A tevent request created with smb1cli_readx_send()
205 * @param[out] received The number of bytes received.
206 * @param[out] rcvbuf Pointer to the bytes received.
208 * @return NT_STATUS_OK on succsess.
210 NTSTATUS smb1cli_readx_recv(struct tevent_req *req,
211 uint32_t *received,
212 uint8_t **rcvbuf)
214 struct smb1cli_readx_state *state = tevent_req_data(
215 req, struct smb1cli_readx_state);
216 NTSTATUS status;
218 if (tevent_req_is_nterror(req, &status)) {
219 return status;
221 *received = state->received;
222 *rcvbuf = state->buf;
223 return NT_STATUS_OK;