/src/samba/libcli/smb/smb1cli_write.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | Copyright (C) Gregor Beck 2013 |
5 | | |
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. |
10 | | |
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. |
15 | | |
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/>. |
18 | | */ |
19 | | |
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" |
25 | | |
26 | | struct smb1cli_writex_state { |
27 | | uint32_t size; |
28 | | uint16_t vwv[14]; |
29 | | uint32_t written; |
30 | | uint16_t available; |
31 | | uint8_t pad; |
32 | | struct iovec iov[2]; |
33 | | }; |
34 | | |
35 | | static void smb1cli_writex_done(struct tevent_req *subreq); |
36 | | |
37 | | /** |
38 | | * Send an asynchrounus SMB_COM_WRITE_ANDX request. |
39 | | * <a href="http://msdn.microsoft.com/en-us/library/ee441954.aspx">MS-CIFS 2.2.4.43.1</a> |
40 | | * @see smb1cli_writex_recv(), smb1cli_writex() |
41 | | * |
42 | | * @param[in] mem_ctx The memory context for the result. |
43 | | * @param[in] ev The event context to work on. |
44 | | * @param[in] conn The smb connection. |
45 | | * @param[in] timeout_msec If positive a timeout for the request. |
46 | | * @param[in] pid The process identifier |
47 | | * @param[in] tcon The smb tree connect. |
48 | | * @param[in] session The smb session. |
49 | | * @param[in] fnum The file id of the file the data should be written to. |
50 | | * @param[in] mode A bitfield containing the write mode. |
51 | | * @param[in] buf The data to be written to the file. |
52 | | * @param[in] offset The offset in bytes from the begin of file where to write. |
53 | | * @param[in] size The number of bytes to write. |
54 | | * |
55 | | * @return a tevent_req or NULL |
56 | | */ |
57 | | struct tevent_req *smb1cli_writex_send(TALLOC_CTX *mem_ctx, |
58 | | struct tevent_context *ev, |
59 | | struct smbXcli_conn *conn, |
60 | | uint32_t timeout_msec, |
61 | | uint32_t pid, |
62 | | struct smbXcli_tcon *tcon, |
63 | | struct smbXcli_session *session, |
64 | | uint16_t fnum, |
65 | | uint16_t mode, |
66 | | const uint8_t *buf, |
67 | | uint64_t offset, |
68 | | uint32_t size) |
69 | 0 | { |
70 | 0 | struct tevent_req *req, *subreq; |
71 | 0 | struct smb1cli_writex_state *state; |
72 | 0 | bool bigoffset = ((smb1cli_conn_capabilities(conn) & CAP_LARGE_FILES) != 0); |
73 | 0 | uint8_t wct = bigoffset ? 14 : 12; |
74 | 0 | uint16_t *vwv; |
75 | 0 | uint16_t data_offset = |
76 | 0 | smb1cli_req_wct_ofs(NULL, 0) /* reqs_before */ |
77 | 0 | + 1 /* the wct field */ |
78 | 0 | + wct * 2 /* vwv */ |
79 | 0 | + 2 /* num_bytes field */ |
80 | 0 | + 1; /* pad */ |
81 | 0 | NTSTATUS status; |
82 | |
|
83 | 0 | req = tevent_req_create(mem_ctx, &state, struct smb1cli_writex_state); |
84 | 0 | if (req == NULL) { |
85 | 0 | return NULL; |
86 | 0 | } |
87 | | |
88 | 0 | state->size = size; |
89 | |
|
90 | 0 | vwv = state->vwv; |
91 | |
|
92 | 0 | SCVAL(vwv+0, 0, 0xFF); |
93 | 0 | SCVAL(vwv+0, 1, 0); |
94 | 0 | SSVAL(vwv+1, 0, 0); |
95 | 0 | SSVAL(vwv+2, 0, fnum); |
96 | 0 | SIVAL(vwv+3, 0, offset); |
97 | 0 | SIVAL(vwv+5, 0, 0); |
98 | 0 | SSVAL(vwv+7, 0, mode); |
99 | 0 | SSVAL(vwv+8, 0, 0); |
100 | 0 | SSVAL(vwv+9, 0, (state->size>>16)); |
101 | 0 | SSVAL(vwv+10, 0, state->size); |
102 | 0 | SSVAL(vwv+11, 0, data_offset); |
103 | |
|
104 | 0 | if (bigoffset) { |
105 | 0 | SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff); |
106 | 0 | } |
107 | |
|
108 | 0 | state->pad = 0; |
109 | 0 | state->iov[0].iov_base = (void *)&state->pad; |
110 | 0 | state->iov[0].iov_len = 1; |
111 | 0 | state->iov[1].iov_base = discard_const_p(void, buf); |
112 | 0 | state->iov[1].iov_len = state->size; |
113 | |
|
114 | 0 | subreq = smb1cli_req_create(state, ev, conn, SMBwriteX, |
115 | 0 | 0, 0, /* *_flags */ |
116 | 0 | 0, 0, /* *_flags2 */ |
117 | 0 | timeout_msec, pid, tcon, session, |
118 | 0 | wct, vwv, |
119 | 0 | ARRAY_SIZE(state->iov), state->iov); |
120 | 0 | if (tevent_req_nomem(subreq, req)) { |
121 | 0 | return tevent_req_post(req, ev); |
122 | 0 | } |
123 | 0 | tevent_req_set_callback(subreq, smb1cli_writex_done, req); |
124 | |
|
125 | 0 | status = smb1cli_req_chain_submit(&subreq, 1); |
126 | 0 | if (tevent_req_nterror(req, status)) { |
127 | 0 | return tevent_req_post(req, ev); |
128 | 0 | } |
129 | | |
130 | 0 | return req; |
131 | 0 | } |
132 | | |
133 | | static void smb1cli_writex_done(struct tevent_req *subreq) |
134 | 0 | { |
135 | 0 | struct tevent_req *req = tevent_req_callback_data( |
136 | 0 | subreq, struct tevent_req); |
137 | 0 | struct smb1cli_writex_state *state = tevent_req_data( |
138 | 0 | req, struct smb1cli_writex_state); |
139 | 0 | struct iovec *recv_iov = NULL; |
140 | 0 | uint8_t wct; |
141 | 0 | uint16_t *vwv; |
142 | 0 | NTSTATUS status; |
143 | 0 | static const struct smb1cli_req_expected_response expected[] = { |
144 | 0 | { |
145 | 0 | .status = NT_STATUS_OK, |
146 | 0 | .wct = 0x06 |
147 | 0 | }, |
148 | 0 | }; |
149 | |
|
150 | 0 | status = smb1cli_req_recv(subreq, state, |
151 | 0 | &recv_iov, |
152 | 0 | NULL, /* phdr */ |
153 | 0 | &wct, |
154 | 0 | &vwv, |
155 | 0 | NULL, /* pvwv_offset */ |
156 | 0 | NULL, /* num_bytes */ |
157 | 0 | NULL, /* bytes */ |
158 | 0 | NULL, /* pbytes_offset */ |
159 | 0 | NULL, /* inbuf */ |
160 | 0 | expected, ARRAY_SIZE(expected)); |
161 | 0 | TALLOC_FREE(subreq); |
162 | 0 | if (tevent_req_nterror(req, status)) { |
163 | 0 | return; |
164 | 0 | } |
165 | | |
166 | 0 | state->written = SVAL(vwv+2, 0); |
167 | 0 | if (state->size > UINT16_MAX) { |
168 | | /* |
169 | | * It is important that we only set the |
170 | | * high bits only if we asked for a large write. |
171 | | * |
172 | | * OS/2 print shares get this wrong and may send |
173 | | * invalid values. |
174 | | * |
175 | | * See bug #5326. |
176 | | */ |
177 | 0 | state->written |= SVAL(vwv+4, 0)<<16; |
178 | 0 | } |
179 | 0 | state->available = SVAL(vwv+3, 0); |
180 | |
|
181 | 0 | tevent_req_done(req); |
182 | 0 | } |
183 | | |
184 | | /** |
185 | | * Receive the response to an asynchronous SMB_COM_WRITE_ANDX request. |
186 | | * <a href="http://msdn.microsoft.com/en-us/library/ee441673.aspx">MS-CIFS:2.2.4.43.2</a> |
187 | | * |
188 | | * |
189 | | * @param[in] req req A tevent request created with smb1cli_writex_send() |
190 | | * @param[out] pwritten The number of bytes written to the file. |
191 | | * @param[out] pavailable Valid if writing to a named pipe or IO device. |
192 | | * |
193 | | * @return NT_STATUS_OK on success. |
194 | | */ |
195 | | NTSTATUS smb1cli_writex_recv(struct tevent_req *req, uint32_t *pwritten, uint16_t *pavailable) |
196 | 0 | { |
197 | 0 | struct smb1cli_writex_state *state = tevent_req_data( |
198 | 0 | req, struct smb1cli_writex_state); |
199 | 0 | NTSTATUS status; |
200 | |
|
201 | 0 | if (tevent_req_is_nterror(req, &status)) { |
202 | 0 | return status; |
203 | 0 | } |
204 | 0 | if (pwritten != NULL) { |
205 | 0 | *pwritten = state->written; |
206 | 0 | } |
207 | 0 | if (pavailable != NULL) { |
208 | 0 | *pavailable = state->available; |
209 | 0 | } |
210 | 0 | return NT_STATUS_OK; |
211 | 0 | } |
212 | | |
213 | | /** |
214 | | * Send an synchrounus SMB_COM_WRITE_ANDX request. |
215 | | * <a href="http://msdn.microsoft.com/en-us/library/ee441848.aspx">MS-CIFS 2.2.4.43</a> |
216 | | * @see smb1cli_writex_send(), smb1cli_writex_recv() |
217 | | * |
218 | | * @param[in] conn The smb connection. |
219 | | * @param[in] timeout_msec If positive a timeout for the request. |
220 | | * @param[in] pid The process identifier |
221 | | * @param[in] tcon The smb tree connect. |
222 | | * @param[in] session The smb session. |
223 | | * @param[in] fnum The file id of the file the data should be written to. |
224 | | * @param[in] mode A bitfield containing the write mode. |
225 | | * @param[in] buf The data to be written to the file. |
226 | | * @param[in] offset The offset in bytes from the begin of file where to write. |
227 | | * @param[in] size The number of bytes to write. |
228 | | * @param[out] pwritten The number of bytes written to the file. |
229 | | * @param[out] pavailable Valid if writing to a named pipe or IO device. |
230 | | * |
231 | | * @return NT_STATUS_OK on success. |
232 | | */ |
233 | | NTSTATUS smb1cli_writex(struct smbXcli_conn *conn, |
234 | | uint32_t timeout_msec, |
235 | | uint32_t pid, |
236 | | struct smbXcli_tcon *tcon, |
237 | | struct smbXcli_session *session, |
238 | | uint16_t fnum, |
239 | | uint16_t mode, |
240 | | const uint8_t *buf, |
241 | | uint64_t offset, |
242 | | uint32_t size, |
243 | | uint32_t *pwritten, |
244 | | uint16_t *pavailable) |
245 | 0 | { |
246 | 0 | TALLOC_CTX *frame = NULL; |
247 | 0 | struct tevent_context *ev; |
248 | 0 | struct tevent_req *req; |
249 | 0 | NTSTATUS status = NT_STATUS_OK; |
250 | |
|
251 | 0 | frame = talloc_stackframe(); |
252 | |
|
253 | 0 | if (smbXcli_conn_has_async_calls(conn)) { |
254 | | /* |
255 | | * Can't use sync call while an async call is in flight |
256 | | */ |
257 | 0 | status = NT_STATUS_INVALID_PARAMETER; |
258 | 0 | goto done; |
259 | 0 | } |
260 | | |
261 | 0 | ev = samba_tevent_context_init(frame); |
262 | 0 | if (ev == NULL) { |
263 | 0 | status = NT_STATUS_NO_MEMORY; |
264 | 0 | goto done; |
265 | 0 | } |
266 | | |
267 | 0 | req = smb1cli_writex_send(frame, ev, conn, |
268 | 0 | timeout_msec, |
269 | 0 | pid, tcon, session, |
270 | 0 | fnum, mode, buf, offset, size); |
271 | 0 | if (req == NULL) { |
272 | 0 | status = NT_STATUS_NO_MEMORY; |
273 | 0 | goto done; |
274 | 0 | } |
275 | | |
276 | 0 | if (!tevent_req_poll_ntstatus(req, ev, &status)) { |
277 | 0 | goto done; |
278 | 0 | } |
279 | | |
280 | 0 | status = smb1cli_writex_recv(req, pwritten, pavailable); |
281 | 0 | done: |
282 | | TALLOC_FREE(frame); |
283 | 0 | return status; |
284 | 0 | } |