ctdb-common: Fix CID 1125583 Dereference after null check (FORWARD_NULL)
[Samba.git] / libcli / smb / smb1cli_read.c
blobd7a7f43e66e107cef7301036b58ae6eb7547e917
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 uint32_t received;
30 uint8_t *buf;
31 bool out_valid;
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 NTSTATUS status;
135 static const struct smb1cli_req_expected_response expected[] = {
137 .status = NT_STATUS_OK,
138 .wct = 0x0C
141 .status = STATUS_BUFFER_OVERFLOW,
142 .wct = 0x0C
146 status = smb1cli_req_recv(subreq, state,
147 &recv_iov,
148 NULL, /* phdr */
149 &wct,
150 &vwv,
151 NULL, /* pvwv_offset */
152 &num_bytes,
153 &bytes,
154 &bytes_offset,
155 NULL, /* inbuf */
156 expected, ARRAY_SIZE(expected));
157 TALLOC_FREE(subreq);
158 if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) {
159 /* no error */
160 } else {
161 if (tevent_req_nterror(req, status)) {
162 return;
166 /* size is the number of bytes the server returned.
167 * Might be zero. */
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);
174 return;
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);
184 return;
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);
191 return;
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);
196 return;
199 state->buf = bytes + (data_offset - bytes_offset);
201 state->out_valid = true;
203 if (tevent_req_nterror(req, status)) {
204 return;
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,
226 uint32_t *received,
227 uint8_t **rcvbuf)
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) {
234 *received = 0;
235 *rcvbuf = NULL;
236 return status;
238 *received = state->received;
239 *rcvbuf = state->buf;
240 return status;