/src/samba/libcli/smb/tstream_smbXcli_np.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | Copyright (C) Stefan Metzmacher 2010 |
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 "../lib/tsocket/tsocket.h" |
24 | | #include "../lib/tsocket/tsocket_internal.h" |
25 | | #include "smb_common.h" |
26 | | #include "smbXcli_base.h" |
27 | | #include "tstream_smbXcli_np.h" |
28 | | #include "libcli/security/security.h" |
29 | | #include "lib/util/iov_buf.h" |
30 | | |
31 | | static const struct tstream_context_ops tstream_smbXcli_np_ops; |
32 | | |
33 | 0 | #define TSTREAM_SMBXCLI_NP_DESIRED_ACCESS ( \ |
34 | 0 | SEC_STD_READ_CONTROL | \ |
35 | 0 | SEC_FILE_READ_DATA | \ |
36 | 0 | SEC_FILE_WRITE_DATA | \ |
37 | 0 | SEC_FILE_APPEND_DATA | \ |
38 | 0 | SEC_FILE_READ_EA | \ |
39 | 0 | SEC_FILE_WRITE_EA | \ |
40 | 0 | SEC_FILE_READ_ATTRIBUTE | \ |
41 | 0 | SEC_FILE_WRITE_ATTRIBUTE | \ |
42 | 0 | 0) |
43 | | |
44 | | struct tstream_smbXcli_np_ref; |
45 | | |
46 | | struct tstream_smbXcli_np { |
47 | | struct smbXcli_conn *conn; |
48 | | struct tstream_smbXcli_np_ref *conn_ref; |
49 | | struct smbXcli_session *session; |
50 | | struct tstream_smbXcli_np_ref *session_ref; |
51 | | struct smbXcli_tcon *tcon; |
52 | | struct tstream_smbXcli_np_ref *tcon_ref; |
53 | | uint16_t pid; |
54 | | unsigned int timeout; |
55 | | |
56 | | const char *npipe; |
57 | | bool is_smb1; |
58 | | uint16_t fnum; |
59 | | uint64_t fid_persistent; |
60 | | uint64_t fid_volatile; |
61 | | uint32_t max_data; |
62 | | |
63 | | struct { |
64 | | bool active; |
65 | | struct tevent_req *read_req; |
66 | | struct tevent_req *write_req; |
67 | | uint16_t setup[2]; |
68 | | } trans; |
69 | | |
70 | | struct { |
71 | | off_t ofs; |
72 | | size_t left; |
73 | | uint8_t *buf; |
74 | | } read, write; |
75 | | }; |
76 | | |
77 | | struct tstream_smbXcli_np_ref { |
78 | | struct tstream_smbXcli_np *cli_nps; |
79 | | }; |
80 | | |
81 | | static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps) |
82 | 0 | { |
83 | 0 | NTSTATUS status; |
84 | |
|
85 | 0 | if (cli_nps->conn_ref != NULL) { |
86 | 0 | cli_nps->conn_ref->cli_nps = NULL; |
87 | 0 | TALLOC_FREE(cli_nps->conn_ref); |
88 | 0 | } |
89 | |
|
90 | 0 | if (cli_nps->session_ref != NULL) { |
91 | 0 | cli_nps->session_ref->cli_nps = NULL; |
92 | 0 | TALLOC_FREE(cli_nps->session_ref); |
93 | 0 | } |
94 | |
|
95 | 0 | if (cli_nps->tcon_ref != NULL) { |
96 | 0 | cli_nps->tcon_ref->cli_nps = NULL; |
97 | 0 | TALLOC_FREE(cli_nps->tcon_ref); |
98 | 0 | } |
99 | |
|
100 | 0 | if (!smbXcli_conn_is_connected(cli_nps->conn)) { |
101 | 0 | return 0; |
102 | 0 | } |
103 | | |
104 | | /* |
105 | | * TODO: do not use a sync call with a destructor!!! |
106 | | * |
107 | | * This only happens, if a caller does talloc_free(), |
108 | | * while the everything was still ok. |
109 | | * |
110 | | * If we get an unexpected failure within a normal |
111 | | * operation, we already do an async cli_close_send()/_recv(). |
112 | | * |
113 | | * Once we've fixed all callers to call |
114 | | * tstream_disconnect_send()/_recv(), this will |
115 | | * never be called. |
116 | | * |
117 | | * We use a maximum timeout of 1 second == 1000 msec. |
118 | | */ |
119 | 0 | cli_nps->timeout = MIN(cli_nps->timeout, 1000); |
120 | |
|
121 | 0 | if (cli_nps->is_smb1) { |
122 | 0 | status = smb1cli_close(cli_nps->conn, |
123 | 0 | cli_nps->timeout, |
124 | 0 | cli_nps->pid, |
125 | 0 | cli_nps->tcon, |
126 | 0 | cli_nps->session, |
127 | 0 | cli_nps->fnum, UINT32_MAX); |
128 | 0 | } else { |
129 | 0 | status = smb2cli_close(cli_nps->conn, |
130 | 0 | cli_nps->timeout, |
131 | 0 | cli_nps->session, |
132 | 0 | cli_nps->tcon, |
133 | 0 | 0, /* flags */ |
134 | 0 | cli_nps->fid_persistent, |
135 | 0 | cli_nps->fid_volatile); |
136 | 0 | } |
137 | 0 | if (!NT_STATUS_IS_OK(status)) { |
138 | 0 | DEBUG(1, ("tstream_smbXcli_np_destructor: cli_close " |
139 | 0 | "failed on pipe %s. Error was %s\n", |
140 | 0 | cli_nps->npipe, nt_errstr(status))); |
141 | 0 | } |
142 | | /* |
143 | | * We can't do much on failure |
144 | | */ |
145 | 0 | return 0; |
146 | 0 | } |
147 | | |
148 | | static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref) |
149 | 0 | { |
150 | 0 | if (ref->cli_nps == NULL) { |
151 | 0 | return 0; |
152 | 0 | } |
153 | | |
154 | 0 | if (ref->cli_nps->conn == NULL) { |
155 | 0 | return 0; |
156 | 0 | } |
157 | | |
158 | 0 | ref->cli_nps->conn = NULL; |
159 | 0 | ref->cli_nps->session = NULL; |
160 | 0 | ref->cli_nps->tcon = NULL; |
161 | |
|
162 | 0 | TALLOC_FREE(ref->cli_nps->conn_ref); |
163 | 0 | TALLOC_FREE(ref->cli_nps->session_ref); |
164 | 0 | TALLOC_FREE(ref->cli_nps->tcon_ref); |
165 | |
|
166 | 0 | return 0; |
167 | 0 | }; |
168 | | |
169 | | static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx, |
170 | | struct tevent_context *ev, |
171 | | struct tstream_context *stream); |
172 | | static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req, |
173 | | int *perrno); |
174 | | |
175 | | struct tstream_smbXcli_np_open_state { |
176 | | struct smbXcli_conn *conn; |
177 | | struct smbXcli_session *session; |
178 | | struct smbXcli_tcon *tcon; |
179 | | uint16_t pid; |
180 | | unsigned int timeout; |
181 | | |
182 | | bool is_smb1; |
183 | | uint16_t fnum; |
184 | | uint64_t fid_persistent; |
185 | | uint64_t fid_volatile; |
186 | | const char *npipe; |
187 | | }; |
188 | | |
189 | | static void tstream_smbXcli_np_open_done(struct tevent_req *subreq); |
190 | | |
191 | | struct tevent_req *tstream_smbXcli_np_open_send(TALLOC_CTX *mem_ctx, |
192 | | struct tevent_context *ev, |
193 | | struct smbXcli_conn *conn, |
194 | | struct smbXcli_session *session, |
195 | | struct smbXcli_tcon *tcon, |
196 | | uint16_t pid, |
197 | | unsigned int timeout, |
198 | | const char *npipe) |
199 | 0 | { |
200 | 0 | struct tevent_req *req; |
201 | 0 | struct tstream_smbXcli_np_open_state *state; |
202 | 0 | struct tevent_req *subreq; |
203 | |
|
204 | 0 | req = tevent_req_create(mem_ctx, &state, |
205 | 0 | struct tstream_smbXcli_np_open_state); |
206 | 0 | if (!req) { |
207 | 0 | return NULL; |
208 | 0 | } |
209 | 0 | state->conn = conn; |
210 | 0 | state->tcon = tcon; |
211 | 0 | state->session = session; |
212 | 0 | state->pid = pid; |
213 | 0 | state->timeout = timeout; |
214 | |
|
215 | 0 | state->npipe = talloc_strdup(state, npipe); |
216 | 0 | if (tevent_req_nomem(state->npipe, req)) { |
217 | 0 | return tevent_req_post(req, ev); |
218 | 0 | } |
219 | | |
220 | 0 | if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) { |
221 | 0 | state->is_smb1 = true; |
222 | 0 | } |
223 | |
|
224 | 0 | if (state->is_smb1) { |
225 | 0 | const char *smb1_npipe; |
226 | | |
227 | | /* |
228 | | * Windows and newer Samba versions allow |
229 | | * the pipe name without leading backslash, |
230 | | * but we should better behave like windows clients |
231 | | */ |
232 | 0 | smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe); |
233 | 0 | if (tevent_req_nomem(smb1_npipe, req)) { |
234 | 0 | return tevent_req_post(req, ev); |
235 | 0 | } |
236 | 0 | subreq = smb1cli_ntcreatex_send(state, ev, state->conn, |
237 | 0 | state->timeout, |
238 | 0 | state->pid, |
239 | 0 | state->tcon, |
240 | 0 | state->session, |
241 | 0 | smb1_npipe, |
242 | 0 | 0, /* CreatFlags */ |
243 | 0 | 0, /* RootDirectoryFid */ |
244 | 0 | TSTREAM_SMBXCLI_NP_DESIRED_ACCESS, |
245 | 0 | 0, /* AllocationSize */ |
246 | 0 | 0, /* FileAttributes */ |
247 | 0 | FILE_SHARE_READ|FILE_SHARE_WRITE, |
248 | 0 | FILE_OPEN, /* CreateDisposition */ |
249 | 0 | 0, /* CreateOptions */ |
250 | 0 | 2, /* NTCREATEX_IMPERSONATION_IMPERSONATION */ |
251 | 0 | 0); /* SecurityFlags */ |
252 | 0 | } else { |
253 | 0 | subreq = smb2cli_create_send(state, ev, state->conn, |
254 | 0 | state->timeout, state->session, |
255 | 0 | state->tcon, |
256 | 0 | npipe, |
257 | 0 | SMB2_OPLOCK_LEVEL_NONE, |
258 | 0 | SMB2_IMPERSONATION_IMPERSONATION, |
259 | 0 | TSTREAM_SMBXCLI_NP_DESIRED_ACCESS, |
260 | 0 | 0, /* file_attributes */ |
261 | 0 | FILE_SHARE_READ|FILE_SHARE_WRITE, |
262 | 0 | FILE_OPEN, |
263 | 0 | 0, /* create_options */ |
264 | 0 | NULL); /* blobs */ |
265 | 0 | } |
266 | 0 | if (tevent_req_nomem(subreq, req)) { |
267 | 0 | return tevent_req_post(req, ev); |
268 | 0 | } |
269 | 0 | tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req); |
270 | |
|
271 | 0 | return req; |
272 | 0 | } |
273 | | |
274 | | static void tstream_smbXcli_np_open_done(struct tevent_req *subreq) |
275 | 0 | { |
276 | 0 | struct tevent_req *req = |
277 | 0 | tevent_req_callback_data(subreq, struct tevent_req); |
278 | 0 | struct tstream_smbXcli_np_open_state *state = |
279 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_open_state); |
280 | 0 | NTSTATUS status; |
281 | |
|
282 | 0 | if (state->is_smb1) { |
283 | 0 | status = smb1cli_ntcreatex_recv(subreq, &state->fnum); |
284 | 0 | } else { |
285 | 0 | status = smb2cli_create_recv( |
286 | 0 | subreq, |
287 | 0 | &state->fid_persistent, |
288 | 0 | &state->fid_volatile, |
289 | 0 | NULL, |
290 | 0 | NULL, |
291 | 0 | NULL, |
292 | 0 | NULL); |
293 | 0 | } |
294 | 0 | TALLOC_FREE(subreq); |
295 | 0 | if (!NT_STATUS_IS_OK(status)) { |
296 | 0 | tevent_req_nterror(req, status); |
297 | 0 | return; |
298 | 0 | } |
299 | | |
300 | 0 | tevent_req_done(req); |
301 | 0 | } |
302 | | |
303 | | NTSTATUS _tstream_smbXcli_np_open_recv(struct tevent_req *req, |
304 | | TALLOC_CTX *mem_ctx, |
305 | | struct tstream_context **_stream, |
306 | | const char *location) |
307 | 0 | { |
308 | 0 | struct tstream_smbXcli_np_open_state *state = |
309 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_open_state); |
310 | 0 | struct tstream_context *stream; |
311 | 0 | struct tstream_smbXcli_np *cli_nps; |
312 | 0 | NTSTATUS status; |
313 | |
|
314 | 0 | if (tevent_req_is_nterror(req, &status)) { |
315 | 0 | tevent_req_received(req); |
316 | 0 | return status; |
317 | 0 | } |
318 | | |
319 | 0 | stream = tstream_context_create(mem_ctx, |
320 | 0 | &tstream_smbXcli_np_ops, |
321 | 0 | &cli_nps, |
322 | 0 | struct tstream_smbXcli_np, |
323 | 0 | location); |
324 | 0 | if (!stream) { |
325 | 0 | tevent_req_received(req); |
326 | 0 | return NT_STATUS_NO_MEMORY; |
327 | 0 | } |
328 | 0 | ZERO_STRUCTP(cli_nps); |
329 | |
|
330 | 0 | cli_nps->conn_ref = talloc_zero(state->conn, |
331 | 0 | struct tstream_smbXcli_np_ref); |
332 | 0 | if (cli_nps->conn_ref == NULL) { |
333 | 0 | TALLOC_FREE(cli_nps); |
334 | 0 | tevent_req_received(req); |
335 | 0 | return NT_STATUS_NO_MEMORY; |
336 | 0 | } |
337 | 0 | cli_nps->conn_ref->cli_nps = cli_nps; |
338 | |
|
339 | 0 | cli_nps->session_ref = talloc_zero(state->session, |
340 | 0 | struct tstream_smbXcli_np_ref); |
341 | 0 | if (cli_nps->session_ref == NULL) { |
342 | 0 | TALLOC_FREE(cli_nps); |
343 | 0 | tevent_req_received(req); |
344 | 0 | return NT_STATUS_NO_MEMORY; |
345 | 0 | } |
346 | 0 | cli_nps->session_ref->cli_nps = cli_nps; |
347 | |
|
348 | 0 | cli_nps->tcon_ref = talloc_zero(state->tcon, |
349 | 0 | struct tstream_smbXcli_np_ref); |
350 | 0 | if (cli_nps->tcon_ref == NULL) { |
351 | 0 | TALLOC_FREE(cli_nps); |
352 | 0 | tevent_req_received(req); |
353 | 0 | return NT_STATUS_NO_MEMORY; |
354 | 0 | } |
355 | 0 | cli_nps->tcon_ref->cli_nps = cli_nps; |
356 | |
|
357 | 0 | cli_nps->conn = state->conn; |
358 | 0 | cli_nps->session = state->session; |
359 | 0 | cli_nps->tcon = state->tcon; |
360 | 0 | cli_nps->pid = state->pid; |
361 | 0 | cli_nps->timeout = state->timeout; |
362 | 0 | cli_nps->npipe = talloc_move(cli_nps, &state->npipe); |
363 | 0 | cli_nps->is_smb1 = state->is_smb1; |
364 | 0 | cli_nps->fnum = state->fnum; |
365 | 0 | cli_nps->fid_persistent = state->fid_persistent; |
366 | 0 | cli_nps->fid_volatile = state->fid_volatile; |
367 | 0 | cli_nps->max_data = TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE; |
368 | |
|
369 | 0 | talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor); |
370 | 0 | talloc_set_destructor(cli_nps->conn_ref, |
371 | 0 | tstream_smbXcli_np_ref_destructor); |
372 | 0 | talloc_set_destructor(cli_nps->session_ref, |
373 | 0 | tstream_smbXcli_np_ref_destructor); |
374 | 0 | talloc_set_destructor(cli_nps->tcon_ref, |
375 | 0 | tstream_smbXcli_np_ref_destructor); |
376 | |
|
377 | 0 | cli_nps->trans.active = false; |
378 | 0 | cli_nps->trans.read_req = NULL; |
379 | 0 | cli_nps->trans.write_req = NULL; |
380 | 0 | SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD); |
381 | 0 | SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum); |
382 | |
|
383 | 0 | *_stream = stream; |
384 | 0 | tevent_req_received(req); |
385 | 0 | return NT_STATUS_OK; |
386 | 0 | } |
387 | | |
388 | | static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream) |
389 | 0 | { |
390 | 0 | struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream, |
391 | 0 | struct tstream_smbXcli_np); |
392 | |
|
393 | 0 | if (!smbXcli_conn_is_connected(cli_nps->conn)) { |
394 | 0 | errno = ENOTCONN; |
395 | 0 | return -1; |
396 | 0 | } |
397 | | |
398 | 0 | return cli_nps->read.left; |
399 | 0 | } |
400 | | |
401 | | bool tstream_is_smbXcli_np(struct tstream_context *stream) |
402 | 0 | { |
403 | 0 | struct tstream_smbXcli_np *cli_nps = |
404 | 0 | talloc_get_type(_tstream_context_data(stream), |
405 | 0 | struct tstream_smbXcli_np); |
406 | |
|
407 | 0 | if (!cli_nps) { |
408 | 0 | return false; |
409 | 0 | } |
410 | | |
411 | 0 | return true; |
412 | 0 | } |
413 | | |
414 | | NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream) |
415 | 0 | { |
416 | 0 | struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream, |
417 | 0 | struct tstream_smbXcli_np); |
418 | |
|
419 | 0 | if (cli_nps->trans.read_req) { |
420 | 0 | return NT_STATUS_PIPE_BUSY; |
421 | 0 | } |
422 | | |
423 | 0 | if (cli_nps->trans.write_req) { |
424 | 0 | return NT_STATUS_PIPE_BUSY; |
425 | 0 | } |
426 | | |
427 | 0 | if (cli_nps->trans.active) { |
428 | 0 | return NT_STATUS_PIPE_BUSY; |
429 | 0 | } |
430 | | |
431 | 0 | cli_nps->trans.active = true; |
432 | |
|
433 | 0 | return NT_STATUS_OK; |
434 | 0 | } |
435 | | |
436 | | void tstream_smbXcli_np_set_max_data(struct tstream_context *stream, |
437 | | uint32_t max_data) |
438 | 0 | { |
439 | 0 | struct tstream_smbXcli_np *cli_nps = tstream_context_data( |
440 | 0 | stream, struct tstream_smbXcli_np); |
441 | |
|
442 | 0 | cli_nps->max_data = max_data; |
443 | 0 | } |
444 | | |
445 | | unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream, |
446 | | unsigned int timeout) |
447 | 0 | { |
448 | 0 | struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream, |
449 | 0 | struct tstream_smbXcli_np); |
450 | 0 | unsigned int old_timeout = cli_nps->timeout; |
451 | |
|
452 | 0 | cli_nps->timeout = timeout; |
453 | 0 | return old_timeout; |
454 | 0 | } |
455 | | |
456 | | struct tstream_smbXcli_np_writev_state { |
457 | | struct tstream_context *stream; |
458 | | struct tevent_context *ev; |
459 | | |
460 | | struct iovec *vector; |
461 | | size_t count; |
462 | | |
463 | | int ret; |
464 | | |
465 | | struct { |
466 | | int val; |
467 | | const char *location; |
468 | | } error; |
469 | | }; |
470 | | |
471 | | static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state) |
472 | 0 | { |
473 | 0 | struct tstream_smbXcli_np *cli_nps = |
474 | 0 | tstream_context_data(state->stream, |
475 | 0 | struct tstream_smbXcli_np); |
476 | |
|
477 | 0 | cli_nps->trans.write_req = NULL; |
478 | |
|
479 | 0 | return 0; |
480 | 0 | } |
481 | | |
482 | | static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req); |
483 | | |
484 | | static struct tevent_req *tstream_smbXcli_np_writev_send(TALLOC_CTX *mem_ctx, |
485 | | struct tevent_context *ev, |
486 | | struct tstream_context *stream, |
487 | | const struct iovec *vector, |
488 | | size_t count) |
489 | 0 | { |
490 | 0 | struct tevent_req *req; |
491 | 0 | struct tstream_smbXcli_np_writev_state *state; |
492 | 0 | struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream, |
493 | 0 | struct tstream_smbXcli_np); |
494 | |
|
495 | 0 | req = tevent_req_create(mem_ctx, &state, |
496 | 0 | struct tstream_smbXcli_np_writev_state); |
497 | 0 | if (!req) { |
498 | 0 | return NULL; |
499 | 0 | } |
500 | 0 | state->stream = stream; |
501 | 0 | state->ev = ev; |
502 | 0 | state->ret = 0; |
503 | |
|
504 | 0 | talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor); |
505 | |
|
506 | 0 | if (!smbXcli_conn_is_connected(cli_nps->conn)) { |
507 | 0 | tevent_req_error(req, ENOTCONN); |
508 | 0 | return tevent_req_post(req, ev); |
509 | 0 | } |
510 | | |
511 | | /* |
512 | | * we make a copy of the vector so we can change the structure |
513 | | */ |
514 | 0 | state->vector = talloc_array(state, struct iovec, count); |
515 | 0 | if (tevent_req_nomem(state->vector, req)) { |
516 | 0 | return tevent_req_post(req, ev); |
517 | 0 | } |
518 | 0 | memcpy(state->vector, vector, sizeof(struct iovec) * count); |
519 | 0 | state->count = count; |
520 | |
|
521 | 0 | tstream_smbXcli_np_writev_write_next(req); |
522 | 0 | if (!tevent_req_is_in_progress(req)) { |
523 | 0 | return tevent_req_post(req, ev); |
524 | 0 | } |
525 | | |
526 | 0 | return req; |
527 | 0 | } |
528 | | |
529 | | static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req); |
530 | | static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq); |
531 | | |
532 | | static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req) |
533 | 0 | { |
534 | 0 | struct tstream_smbXcli_np_writev_state *state = |
535 | 0 | tevent_req_data(req, |
536 | 0 | struct tstream_smbXcli_np_writev_state); |
537 | 0 | struct tstream_smbXcli_np *cli_nps = |
538 | 0 | tstream_context_data(state->stream, |
539 | 0 | struct tstream_smbXcli_np); |
540 | 0 | struct tevent_req *subreq; |
541 | 0 | ssize_t left; |
542 | |
|
543 | 0 | left = iov_buflen(state->vector, state->count); |
544 | |
|
545 | 0 | if (left < 0) { |
546 | 0 | tevent_req_error(req, EMSGSIZE); |
547 | 0 | return; |
548 | 0 | } |
549 | | |
550 | 0 | if (left == 0) { |
551 | 0 | TALLOC_FREE(cli_nps->write.buf); |
552 | 0 | tevent_req_done(req); |
553 | 0 | return; |
554 | 0 | } |
555 | | |
556 | 0 | cli_nps->write.ofs = 0; |
557 | 0 | cli_nps->write.left = MIN(left, cli_nps->max_data); |
558 | 0 | cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf, |
559 | 0 | uint8_t, cli_nps->write.left); |
560 | 0 | if (tevent_req_nomem(cli_nps->write.buf, req)) { |
561 | 0 | return; |
562 | 0 | } |
563 | | |
564 | | /* |
565 | | * copy the pending buffer first |
566 | | */ |
567 | 0 | while (cli_nps->write.left > 0 && state->count > 0) { |
568 | 0 | uint8_t *base = (uint8_t *)state->vector[0].iov_base; |
569 | 0 | size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len); |
570 | |
|
571 | 0 | memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len); |
572 | |
|
573 | 0 | base += len; |
574 | 0 | state->vector[0].iov_base = base; |
575 | 0 | state->vector[0].iov_len -= len; |
576 | |
|
577 | 0 | cli_nps->write.ofs += len; |
578 | 0 | cli_nps->write.left -= len; |
579 | |
|
580 | 0 | if (state->vector[0].iov_len == 0) { |
581 | 0 | state->vector += 1; |
582 | 0 | state->count -= 1; |
583 | 0 | } |
584 | |
|
585 | 0 | state->ret += len; |
586 | 0 | } |
587 | |
|
588 | 0 | if (cli_nps->trans.active && state->count == 0) { |
589 | 0 | cli_nps->trans.active = false; |
590 | 0 | cli_nps->trans.write_req = req; |
591 | 0 | return; |
592 | 0 | } |
593 | | |
594 | 0 | if (cli_nps->trans.read_req && state->count == 0) { |
595 | 0 | cli_nps->trans.write_req = req; |
596 | 0 | tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req); |
597 | 0 | return; |
598 | 0 | } |
599 | | |
600 | 0 | if (cli_nps->is_smb1) { |
601 | 0 | subreq = smb1cli_writex_send(state, state->ev, |
602 | 0 | cli_nps->conn, |
603 | 0 | cli_nps->timeout, |
604 | 0 | cli_nps->pid, |
605 | 0 | cli_nps->tcon, |
606 | 0 | cli_nps->session, |
607 | 0 | cli_nps->fnum, |
608 | 0 | 8, /* 8 means message mode. */ |
609 | 0 | cli_nps->write.buf, |
610 | 0 | 0, /* offset */ |
611 | 0 | cli_nps->write.ofs); /* size */ |
612 | 0 | } else { |
613 | 0 | subreq = smb2cli_write_send(state, state->ev, |
614 | 0 | cli_nps->conn, |
615 | 0 | cli_nps->timeout, |
616 | 0 | cli_nps->session, |
617 | 0 | cli_nps->tcon, |
618 | 0 | cli_nps->write.ofs, /* length */ |
619 | 0 | 0, /* offset */ |
620 | 0 | cli_nps->fid_persistent, |
621 | 0 | cli_nps->fid_volatile, |
622 | 0 | 0, /* remaining_bytes */ |
623 | 0 | 0, /* flags */ |
624 | 0 | cli_nps->write.buf); |
625 | 0 | } |
626 | 0 | if (tevent_req_nomem(subreq, req)) { |
627 | 0 | return; |
628 | 0 | } |
629 | 0 | tevent_req_set_callback(subreq, |
630 | 0 | tstream_smbXcli_np_writev_write_done, |
631 | 0 | req); |
632 | 0 | } |
633 | | |
634 | | static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req, |
635 | | int error, |
636 | | const char *location); |
637 | | |
638 | | static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq) |
639 | 0 | { |
640 | 0 | struct tevent_req *req = |
641 | 0 | tevent_req_callback_data(subreq, struct tevent_req); |
642 | 0 | struct tstream_smbXcli_np_writev_state *state = |
643 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_writev_state); |
644 | 0 | struct tstream_smbXcli_np *cli_nps = |
645 | 0 | tstream_context_data(state->stream, |
646 | 0 | struct tstream_smbXcli_np); |
647 | 0 | uint32_t written; |
648 | 0 | NTSTATUS status; |
649 | |
|
650 | 0 | if (cli_nps->is_smb1) { |
651 | 0 | status = smb1cli_writex_recv(subreq, &written, NULL); |
652 | 0 | } else { |
653 | 0 | status = smb2cli_write_recv(subreq, &written); |
654 | 0 | } |
655 | 0 | TALLOC_FREE(subreq); |
656 | 0 | if (!NT_STATUS_IS_OK(status)) { |
657 | 0 | tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__); |
658 | 0 | return; |
659 | 0 | } |
660 | | |
661 | 0 | if (written != cli_nps->write.ofs) { |
662 | 0 | tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__); |
663 | 0 | return; |
664 | 0 | } |
665 | | |
666 | 0 | tstream_smbXcli_np_writev_write_next(req); |
667 | 0 | } |
668 | | |
669 | | static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq); |
670 | | |
671 | | static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req, |
672 | | int error, |
673 | | const char *location) |
674 | 0 | { |
675 | 0 | struct tstream_smbXcli_np_writev_state *state = |
676 | 0 | tevent_req_data(req, |
677 | 0 | struct tstream_smbXcli_np_writev_state); |
678 | 0 | struct tstream_smbXcli_np *cli_nps = |
679 | 0 | tstream_context_data(state->stream, |
680 | 0 | struct tstream_smbXcli_np); |
681 | 0 | struct tevent_req *subreq; |
682 | |
|
683 | 0 | state->error.val = error; |
684 | 0 | state->error.location = location; |
685 | |
|
686 | 0 | if (!smbXcli_conn_is_connected(cli_nps->conn)) { |
687 | | /* return the original error */ |
688 | 0 | _tevent_req_error(req, state->error.val, state->error.location); |
689 | 0 | return; |
690 | 0 | } |
691 | | |
692 | 0 | subreq = tstream_smbXcli_np_disconnect_send(state, state->ev, |
693 | 0 | state->stream); |
694 | 0 | if (subreq == NULL) { |
695 | | /* return the original error */ |
696 | 0 | _tevent_req_error(req, state->error.val, state->error.location); |
697 | 0 | return; |
698 | 0 | } |
699 | 0 | tevent_req_set_callback(subreq, |
700 | 0 | tstream_smbXcli_np_writev_disconnect_done, |
701 | 0 | req); |
702 | 0 | } |
703 | | |
704 | | static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq) |
705 | 0 | { |
706 | 0 | struct tevent_req *req = |
707 | 0 | tevent_req_callback_data(subreq, struct tevent_req); |
708 | 0 | struct tstream_smbXcli_np_writev_state *state = |
709 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_writev_state); |
710 | 0 | int error; |
711 | |
|
712 | 0 | tstream_smbXcli_np_disconnect_recv(subreq, &error); |
713 | 0 | TALLOC_FREE(subreq); |
714 | | |
715 | | /* return the original error */ |
716 | 0 | _tevent_req_error(req, state->error.val, state->error.location); |
717 | 0 | } |
718 | | |
719 | | static int tstream_smbXcli_np_writev_recv(struct tevent_req *req, |
720 | | int *perrno) |
721 | 0 | { |
722 | 0 | struct tstream_smbXcli_np_writev_state *state = |
723 | 0 | tevent_req_data(req, |
724 | 0 | struct tstream_smbXcli_np_writev_state); |
725 | 0 | int ret; |
726 | |
|
727 | 0 | ret = tsocket_simple_int_recv(req, perrno); |
728 | 0 | if (ret == 0) { |
729 | 0 | ret = state->ret; |
730 | 0 | } |
731 | |
|
732 | 0 | tevent_req_received(req); |
733 | 0 | return ret; |
734 | 0 | } |
735 | | |
736 | | struct tstream_smbXcli_np_readv_state { |
737 | | struct tstream_context *stream; |
738 | | struct tevent_context *ev; |
739 | | |
740 | | struct iovec *vector; |
741 | | size_t count; |
742 | | |
743 | | int ret; |
744 | | |
745 | | struct { |
746 | | struct tevent_immediate *im; |
747 | | } trans; |
748 | | |
749 | | struct { |
750 | | int val; |
751 | | const char *location; |
752 | | } error; |
753 | | }; |
754 | | |
755 | | static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state) |
756 | 0 | { |
757 | 0 | struct tstream_smbXcli_np *cli_nps = |
758 | 0 | tstream_context_data(state->stream, |
759 | 0 | struct tstream_smbXcli_np); |
760 | |
|
761 | 0 | cli_nps->trans.read_req = NULL; |
762 | |
|
763 | 0 | return 0; |
764 | 0 | } |
765 | | |
766 | | static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req); |
767 | | |
768 | | static struct tevent_req *tstream_smbXcli_np_readv_send(TALLOC_CTX *mem_ctx, |
769 | | struct tevent_context *ev, |
770 | | struct tstream_context *stream, |
771 | | struct iovec *vector, |
772 | | size_t count) |
773 | 0 | { |
774 | 0 | struct tevent_req *req; |
775 | 0 | struct tstream_smbXcli_np_readv_state *state; |
776 | 0 | struct tstream_smbXcli_np *cli_nps = |
777 | 0 | tstream_context_data(stream, struct tstream_smbXcli_np); |
778 | |
|
779 | 0 | req = tevent_req_create(mem_ctx, &state, |
780 | 0 | struct tstream_smbXcli_np_readv_state); |
781 | 0 | if (!req) { |
782 | 0 | return NULL; |
783 | 0 | } |
784 | 0 | state->stream = stream; |
785 | 0 | state->ev = ev; |
786 | 0 | state->ret = 0; |
787 | |
|
788 | 0 | talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor); |
789 | |
|
790 | 0 | if (!smbXcli_conn_is_connected(cli_nps->conn)) { |
791 | 0 | tevent_req_error(req, ENOTCONN); |
792 | 0 | return tevent_req_post(req, ev); |
793 | 0 | } |
794 | | |
795 | | /* |
796 | | * we make a copy of the vector so we can change the structure |
797 | | */ |
798 | 0 | state->vector = talloc_array(state, struct iovec, count); |
799 | 0 | if (tevent_req_nomem(state->vector, req)) { |
800 | 0 | return tevent_req_post(req, ev); |
801 | 0 | } |
802 | 0 | memcpy(state->vector, vector, sizeof(struct iovec) * count); |
803 | 0 | state->count = count; |
804 | |
|
805 | 0 | tstream_smbXcli_np_readv_read_next(req); |
806 | 0 | if (!tevent_req_is_in_progress(req)) { |
807 | 0 | return tevent_req_post(req, ev); |
808 | 0 | } |
809 | | |
810 | 0 | return req; |
811 | 0 | } |
812 | | |
813 | | static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq); |
814 | | |
815 | | static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req) |
816 | 0 | { |
817 | 0 | struct tstream_smbXcli_np_readv_state *state = |
818 | 0 | tevent_req_data(req, |
819 | 0 | struct tstream_smbXcli_np_readv_state); |
820 | 0 | struct tstream_smbXcli_np *cli_nps = |
821 | 0 | tstream_context_data(state->stream, |
822 | 0 | struct tstream_smbXcli_np); |
823 | 0 | struct tevent_req *subreq; |
824 | | |
825 | | /* |
826 | | * copy the pending buffer first |
827 | | */ |
828 | 0 | while (cli_nps->read.left > 0 && state->count > 0) { |
829 | 0 | uint8_t *base = (uint8_t *)state->vector[0].iov_base; |
830 | 0 | size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len); |
831 | |
|
832 | 0 | memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len); |
833 | |
|
834 | 0 | base += len; |
835 | 0 | state->vector[0].iov_base = base; |
836 | 0 | state->vector[0].iov_len -= len; |
837 | |
|
838 | 0 | cli_nps->read.ofs += len; |
839 | 0 | cli_nps->read.left -= len; |
840 | |
|
841 | 0 | if (state->vector[0].iov_len == 0) { |
842 | 0 | state->vector += 1; |
843 | 0 | state->count -= 1; |
844 | 0 | } |
845 | |
|
846 | 0 | state->ret += len; |
847 | 0 | } |
848 | |
|
849 | 0 | if (cli_nps->read.left == 0) { |
850 | 0 | TALLOC_FREE(cli_nps->read.buf); |
851 | 0 | } |
852 | |
|
853 | 0 | if (state->count == 0) { |
854 | 0 | tevent_req_done(req); |
855 | 0 | return; |
856 | 0 | } |
857 | | |
858 | 0 | if (cli_nps->trans.active) { |
859 | 0 | cli_nps->trans.active = false; |
860 | 0 | cli_nps->trans.read_req = req; |
861 | 0 | return; |
862 | 0 | } |
863 | | |
864 | 0 | if (cli_nps->trans.write_req) { |
865 | 0 | cli_nps->trans.read_req = req; |
866 | 0 | tstream_smbXcli_np_readv_trans_start(req); |
867 | 0 | return; |
868 | 0 | } |
869 | | |
870 | 0 | if (cli_nps->is_smb1) { |
871 | 0 | subreq = smb1cli_readx_send(state, state->ev, |
872 | 0 | cli_nps->conn, |
873 | 0 | cli_nps->timeout, |
874 | 0 | cli_nps->pid, |
875 | 0 | cli_nps->tcon, |
876 | 0 | cli_nps->session, |
877 | 0 | cli_nps->fnum, |
878 | 0 | 0, /* offset */ |
879 | 0 | cli_nps->max_data); |
880 | 0 | } else { |
881 | 0 | subreq = smb2cli_read_send(state, state->ev, |
882 | 0 | cli_nps->conn, |
883 | 0 | cli_nps->timeout, |
884 | 0 | cli_nps->session, |
885 | 0 | cli_nps->tcon, |
886 | 0 | cli_nps->max_data, /* length */ |
887 | 0 | 0, /* offset */ |
888 | 0 | cli_nps->fid_persistent, |
889 | 0 | cli_nps->fid_volatile, |
890 | 0 | 0, /* minimum_count */ |
891 | 0 | 0); /* remaining_bytes */ |
892 | 0 | } |
893 | 0 | if (tevent_req_nomem(subreq, req)) { |
894 | 0 | return; |
895 | 0 | } |
896 | 0 | tevent_req_set_callback(subreq, |
897 | 0 | tstream_smbXcli_np_readv_read_done, |
898 | 0 | req); |
899 | 0 | } |
900 | | |
901 | | static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq); |
902 | | |
903 | | static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req) |
904 | 0 | { |
905 | 0 | struct tstream_smbXcli_np_readv_state *state = |
906 | 0 | tevent_req_data(req, |
907 | 0 | struct tstream_smbXcli_np_readv_state); |
908 | 0 | struct tstream_smbXcli_np *cli_nps = |
909 | 0 | tstream_context_data(state->stream, |
910 | 0 | struct tstream_smbXcli_np); |
911 | 0 | struct tevent_req *subreq; |
912 | |
|
913 | 0 | state->trans.im = tevent_create_immediate(state); |
914 | 0 | if (tevent_req_nomem(state->trans.im, req)) { |
915 | 0 | return; |
916 | 0 | } |
917 | | |
918 | 0 | if (cli_nps->is_smb1) { |
919 | 0 | subreq = smb1cli_trans_send(state, state->ev, |
920 | 0 | cli_nps->conn, SMBtrans, |
921 | 0 | 0, 0, /* *_flags */ |
922 | 0 | 0, 0, /* *_flags2 */ |
923 | 0 | cli_nps->timeout, |
924 | 0 | cli_nps->pid, |
925 | 0 | cli_nps->tcon, |
926 | 0 | cli_nps->session, |
927 | 0 | "\\PIPE\\", |
928 | 0 | 0, 0, 0, |
929 | 0 | cli_nps->trans.setup, 2, |
930 | 0 | 0, |
931 | 0 | NULL, 0, 0, |
932 | 0 | cli_nps->write.buf, |
933 | 0 | cli_nps->write.ofs, |
934 | 0 | cli_nps->max_data); |
935 | 0 | } else { |
936 | 0 | DATA_BLOB in_input_buffer = data_blob_null; |
937 | 0 | DATA_BLOB in_output_buffer = data_blob_null; |
938 | |
|
939 | 0 | in_input_buffer = data_blob_const(cli_nps->write.buf, |
940 | 0 | cli_nps->write.ofs); |
941 | |
|
942 | 0 | subreq = smb2cli_ioctl_send(state, state->ev, |
943 | 0 | cli_nps->conn, |
944 | 0 | cli_nps->timeout, |
945 | 0 | cli_nps->session, |
946 | 0 | cli_nps->tcon, |
947 | 0 | cli_nps->fid_persistent, |
948 | 0 | cli_nps->fid_volatile, |
949 | 0 | FSCTL_NAMED_PIPE_READ_WRITE, |
950 | 0 | 0, /* in_max_input_length */ |
951 | 0 | &in_input_buffer, |
952 | | /* in_max_output_length */ |
953 | 0 | cli_nps->max_data, |
954 | 0 | &in_output_buffer, |
955 | 0 | SMB2_IOCTL_FLAG_IS_FSCTL); |
956 | 0 | } |
957 | 0 | if (tevent_req_nomem(subreq, req)) { |
958 | 0 | return; |
959 | 0 | } |
960 | 0 | tevent_req_set_callback(subreq, |
961 | 0 | tstream_smbXcli_np_readv_trans_done, |
962 | 0 | req); |
963 | 0 | } |
964 | | |
965 | | static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req, |
966 | | int error, |
967 | | const char *location); |
968 | | static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx, |
969 | | struct tevent_immediate *im, |
970 | | void *private_data); |
971 | | |
972 | | static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq) |
973 | 0 | { |
974 | 0 | struct tevent_req *req = |
975 | 0 | tevent_req_callback_data(subreq, struct tevent_req); |
976 | 0 | struct tstream_smbXcli_np_readv_state *state = |
977 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_readv_state); |
978 | 0 | struct tstream_smbXcli_np *cli_nps = |
979 | 0 | tstream_context_data(state->stream, struct tstream_smbXcli_np); |
980 | 0 | uint8_t *rcvbuf; |
981 | 0 | uint32_t received; |
982 | 0 | NTSTATUS status; |
983 | |
|
984 | 0 | if (cli_nps->is_smb1) { |
985 | 0 | status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL, |
986 | 0 | NULL, 0, NULL, |
987 | 0 | &rcvbuf, 0, &received); |
988 | 0 | } else { |
989 | 0 | DATA_BLOB out_input_buffer = data_blob_null; |
990 | 0 | DATA_BLOB out_output_buffer = data_blob_null; |
991 | |
|
992 | 0 | status = smb2cli_ioctl_recv(subreq, state, |
993 | 0 | &out_input_buffer, |
994 | 0 | &out_output_buffer); |
995 | | |
996 | | /* Note that rcvbuf is not a talloc pointer here */ |
997 | 0 | rcvbuf = out_output_buffer.data; |
998 | 0 | received = out_output_buffer.length; |
999 | 0 | } |
1000 | 0 | TALLOC_FREE(subreq); |
1001 | 0 | if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) { |
1002 | | /* |
1003 | | * STATUS_BUFFER_OVERFLOW means that there's |
1004 | | * more data to read when the named pipe is used |
1005 | | * in message mode (which is the case here). |
1006 | | * |
1007 | | * But we hide this from the caller. |
1008 | | */ |
1009 | 0 | status = NT_STATUS_OK; |
1010 | 0 | } |
1011 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1012 | 0 | tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__); |
1013 | 0 | return; |
1014 | 0 | } |
1015 | | |
1016 | 0 | if (received > cli_nps->max_data) { |
1017 | 0 | tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__); |
1018 | 0 | return; |
1019 | 0 | } |
1020 | | |
1021 | 0 | if (received == 0) { |
1022 | 0 | tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__); |
1023 | 0 | return; |
1024 | 0 | } |
1025 | | |
1026 | 0 | cli_nps->read.ofs = 0; |
1027 | 0 | cli_nps->read.left = received; |
1028 | 0 | cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received); |
1029 | 0 | if (cli_nps->read.buf == NULL) { |
1030 | 0 | TALLOC_FREE(subreq); |
1031 | 0 | tevent_req_oom(req); |
1032 | 0 | return; |
1033 | 0 | } |
1034 | 0 | memcpy(cli_nps->read.buf, rcvbuf, received); |
1035 | |
|
1036 | 0 | if (cli_nps->trans.write_req == NULL) { |
1037 | 0 | tstream_smbXcli_np_readv_read_next(req); |
1038 | 0 | return; |
1039 | 0 | } |
1040 | | |
1041 | 0 | tevent_schedule_immediate(state->trans.im, state->ev, |
1042 | 0 | tstream_smbXcli_np_readv_trans_next, req); |
1043 | |
|
1044 | 0 | tevent_req_done(cli_nps->trans.write_req); |
1045 | 0 | } |
1046 | | |
1047 | | static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx, |
1048 | | struct tevent_immediate *im, |
1049 | | void *private_data) |
1050 | 0 | { |
1051 | 0 | struct tevent_req *req = |
1052 | 0 | talloc_get_type_abort(private_data, |
1053 | 0 | struct tevent_req); |
1054 | |
|
1055 | 0 | tstream_smbXcli_np_readv_read_next(req); |
1056 | 0 | } |
1057 | | |
1058 | | static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq) |
1059 | 0 | { |
1060 | 0 | struct tevent_req *req = |
1061 | 0 | tevent_req_callback_data(subreq, struct tevent_req); |
1062 | 0 | struct tstream_smbXcli_np_readv_state *state = |
1063 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_readv_state); |
1064 | 0 | struct tstream_smbXcli_np *cli_nps = |
1065 | 0 | tstream_context_data(state->stream, struct tstream_smbXcli_np); |
1066 | 0 | uint8_t *rcvbuf; |
1067 | 0 | uint32_t received; |
1068 | 0 | NTSTATUS status; |
1069 | | |
1070 | | /* |
1071 | | * We must free subreq in this function as there is |
1072 | | * a timer event attached to it. |
1073 | | */ |
1074 | |
|
1075 | 0 | if (cli_nps->is_smb1) { |
1076 | 0 | status = smb1cli_readx_recv(subreq, &received, &rcvbuf); |
1077 | 0 | } else { |
1078 | 0 | status = smb2cli_read_recv(subreq, state, &rcvbuf, &received); |
1079 | 0 | } |
1080 | | /* |
1081 | | * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a |
1082 | | * child of that. |
1083 | | */ |
1084 | 0 | if (NT_STATUS_EQUAL(status, STATUS_BUFFER_OVERFLOW)) { |
1085 | | /* |
1086 | | * STATUS_BUFFER_OVERFLOW means that there's |
1087 | | * more data to read when the named pipe is used |
1088 | | * in message mode (which is the case here). |
1089 | | * |
1090 | | * But we hide this from the caller. |
1091 | | */ |
1092 | 0 | status = NT_STATUS_OK; |
1093 | 0 | } |
1094 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1095 | 0 | TALLOC_FREE(subreq); |
1096 | 0 | tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__); |
1097 | 0 | return; |
1098 | 0 | } |
1099 | | |
1100 | 0 | if (received > cli_nps->max_data) { |
1101 | 0 | TALLOC_FREE(subreq); |
1102 | 0 | tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__); |
1103 | 0 | return; |
1104 | 0 | } |
1105 | | |
1106 | 0 | if (received == 0) { |
1107 | 0 | TALLOC_FREE(subreq); |
1108 | 0 | tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__); |
1109 | 0 | return; |
1110 | 0 | } |
1111 | | |
1112 | 0 | cli_nps->read.ofs = 0; |
1113 | 0 | cli_nps->read.left = received; |
1114 | 0 | cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received); |
1115 | 0 | if (cli_nps->read.buf == NULL) { |
1116 | 0 | TALLOC_FREE(subreq); |
1117 | 0 | tevent_req_oom(req); |
1118 | 0 | return; |
1119 | 0 | } |
1120 | 0 | memcpy(cli_nps->read.buf, rcvbuf, received); |
1121 | 0 | TALLOC_FREE(subreq); |
1122 | |
|
1123 | 0 | tstream_smbXcli_np_readv_read_next(req); |
1124 | 0 | } |
1125 | | |
1126 | | static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq); |
1127 | | |
1128 | | static void tstream_smbXcli_np_readv_error(struct tevent_req *req); |
1129 | | |
1130 | | static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req, |
1131 | | int error, |
1132 | | const char *location) |
1133 | 0 | { |
1134 | 0 | struct tstream_smbXcli_np_readv_state *state = |
1135 | 0 | tevent_req_data(req, |
1136 | 0 | struct tstream_smbXcli_np_readv_state); |
1137 | 0 | struct tstream_smbXcli_np *cli_nps = |
1138 | 0 | tstream_context_data(state->stream, |
1139 | 0 | struct tstream_smbXcli_np); |
1140 | 0 | struct tevent_req *subreq; |
1141 | |
|
1142 | 0 | state->error.val = error; |
1143 | 0 | state->error.location = location; |
1144 | |
|
1145 | 0 | if (!smbXcli_conn_is_connected(cli_nps->conn)) { |
1146 | | /* return the original error */ |
1147 | 0 | tstream_smbXcli_np_readv_error(req); |
1148 | 0 | return; |
1149 | 0 | } |
1150 | | |
1151 | 0 | subreq = tstream_smbXcli_np_disconnect_send(state, state->ev, |
1152 | 0 | state->stream); |
1153 | 0 | if (subreq == NULL) { |
1154 | | /* return the original error */ |
1155 | 0 | tstream_smbXcli_np_readv_error(req); |
1156 | 0 | return; |
1157 | 0 | } |
1158 | 0 | tevent_req_set_callback(subreq, |
1159 | 0 | tstream_smbXcli_np_readv_disconnect_done, |
1160 | 0 | req); |
1161 | 0 | } |
1162 | | |
1163 | | static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq) |
1164 | 0 | { |
1165 | 0 | struct tevent_req *req = |
1166 | 0 | tevent_req_callback_data(subreq, struct tevent_req); |
1167 | 0 | int error; |
1168 | |
|
1169 | 0 | tstream_smbXcli_np_disconnect_recv(subreq, &error); |
1170 | 0 | TALLOC_FREE(subreq); |
1171 | |
|
1172 | 0 | tstream_smbXcli_np_readv_error(req); |
1173 | 0 | } |
1174 | | |
1175 | | static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx, |
1176 | | struct tevent_immediate *im, |
1177 | | void *private_data); |
1178 | | |
1179 | | static void tstream_smbXcli_np_readv_error(struct tevent_req *req) |
1180 | 0 | { |
1181 | 0 | struct tstream_smbXcli_np_readv_state *state = |
1182 | 0 | tevent_req_data(req, |
1183 | 0 | struct tstream_smbXcli_np_readv_state); |
1184 | 0 | struct tstream_smbXcli_np *cli_nps = |
1185 | 0 | tstream_context_data(state->stream, |
1186 | 0 | struct tstream_smbXcli_np); |
1187 | |
|
1188 | 0 | if (cli_nps->trans.write_req == NULL) { |
1189 | | /* return the original error */ |
1190 | 0 | _tevent_req_error(req, state->error.val, state->error.location); |
1191 | 0 | return; |
1192 | 0 | } |
1193 | | |
1194 | 0 | if (state->trans.im == NULL) { |
1195 | | /* return the original error */ |
1196 | 0 | _tevent_req_error(req, state->error.val, state->error.location); |
1197 | 0 | return; |
1198 | 0 | } |
1199 | | |
1200 | 0 | tevent_schedule_immediate(state->trans.im, state->ev, |
1201 | 0 | tstream_smbXcli_np_readv_error_trigger, req); |
1202 | | |
1203 | | /* return the original error for writev */ |
1204 | 0 | _tevent_req_error(cli_nps->trans.write_req, |
1205 | 0 | state->error.val, state->error.location); |
1206 | 0 | } |
1207 | | |
1208 | | static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx, |
1209 | | struct tevent_immediate *im, |
1210 | | void *private_data) |
1211 | 0 | { |
1212 | 0 | struct tevent_req *req = |
1213 | 0 | talloc_get_type_abort(private_data, |
1214 | 0 | struct tevent_req); |
1215 | 0 | struct tstream_smbXcli_np_readv_state *state = |
1216 | 0 | tevent_req_data(req, |
1217 | 0 | struct tstream_smbXcli_np_readv_state); |
1218 | | |
1219 | | /* return the original error */ |
1220 | 0 | _tevent_req_error(req, state->error.val, state->error.location); |
1221 | 0 | } |
1222 | | |
1223 | | static int tstream_smbXcli_np_readv_recv(struct tevent_req *req, |
1224 | | int *perrno) |
1225 | 0 | { |
1226 | 0 | struct tstream_smbXcli_np_readv_state *state = |
1227 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_readv_state); |
1228 | 0 | int ret; |
1229 | |
|
1230 | 0 | ret = tsocket_simple_int_recv(req, perrno); |
1231 | 0 | if (ret == 0) { |
1232 | 0 | ret = state->ret; |
1233 | 0 | } |
1234 | |
|
1235 | 0 | tevent_req_received(req); |
1236 | 0 | return ret; |
1237 | 0 | } |
1238 | | |
1239 | | struct tstream_smbXcli_np_disconnect_state { |
1240 | | struct tstream_context *stream; |
1241 | | struct tevent_req *subreq; |
1242 | | }; |
1243 | | |
1244 | | static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq); |
1245 | | static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req, |
1246 | | enum tevent_req_state req_state); |
1247 | | |
1248 | | static struct tevent_req *tstream_smbXcli_np_disconnect_send(TALLOC_CTX *mem_ctx, |
1249 | | struct tevent_context *ev, |
1250 | | struct tstream_context *stream) |
1251 | 0 | { |
1252 | 0 | struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream, |
1253 | 0 | struct tstream_smbXcli_np); |
1254 | 0 | struct tevent_req *req; |
1255 | 0 | struct tstream_smbXcli_np_disconnect_state *state; |
1256 | 0 | struct tevent_req *subreq; |
1257 | |
|
1258 | 0 | req = tevent_req_create(mem_ctx, &state, |
1259 | 0 | struct tstream_smbXcli_np_disconnect_state); |
1260 | 0 | if (req == NULL) { |
1261 | 0 | return NULL; |
1262 | 0 | } |
1263 | | |
1264 | 0 | state->stream = stream; |
1265 | |
|
1266 | 0 | if (!smbXcli_conn_is_connected(cli_nps->conn)) { |
1267 | 0 | tevent_req_error(req, ENOTCONN); |
1268 | 0 | return tevent_req_post(req, ev); |
1269 | 0 | } |
1270 | | |
1271 | 0 | if (cli_nps->is_smb1) { |
1272 | 0 | subreq = smb1cli_close_send(state, ev, cli_nps->conn, |
1273 | 0 | cli_nps->timeout, |
1274 | 0 | cli_nps->pid, |
1275 | 0 | cli_nps->tcon, |
1276 | 0 | cli_nps->session, |
1277 | 0 | cli_nps->fnum, UINT32_MAX); |
1278 | 0 | } else { |
1279 | 0 | subreq = smb2cli_close_send(state, ev, cli_nps->conn, |
1280 | 0 | cli_nps->timeout, |
1281 | 0 | cli_nps->session, |
1282 | 0 | cli_nps->tcon, |
1283 | 0 | 0, /* flags */ |
1284 | 0 | cli_nps->fid_persistent, |
1285 | 0 | cli_nps->fid_volatile); |
1286 | 0 | } |
1287 | 0 | if (tevent_req_nomem(subreq, req)) { |
1288 | 0 | return tevent_req_post(req, ev); |
1289 | 0 | } |
1290 | 0 | tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req); |
1291 | 0 | state->subreq = subreq; |
1292 | |
|
1293 | 0 | tevent_req_set_cleanup_fn(req, tstream_smbXcli_np_disconnect_cleanup); |
1294 | | |
1295 | | /* |
1296 | | * Make sure we don't send any requests anymore. |
1297 | | */ |
1298 | 0 | cli_nps->conn = NULL; |
1299 | |
|
1300 | 0 | return req; |
1301 | 0 | } |
1302 | | |
1303 | | static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq) |
1304 | 0 | { |
1305 | 0 | struct tevent_req *req = tevent_req_callback_data(subreq, |
1306 | 0 | struct tevent_req); |
1307 | 0 | struct tstream_smbXcli_np_disconnect_state *state = |
1308 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state); |
1309 | 0 | struct tstream_smbXcli_np *cli_nps = |
1310 | 0 | tstream_context_data(state->stream, struct tstream_smbXcli_np); |
1311 | 0 | NTSTATUS status; |
1312 | |
|
1313 | 0 | state->subreq = NULL; |
1314 | |
|
1315 | 0 | if (cli_nps->is_smb1) { |
1316 | 0 | status = smb1cli_close_recv(subreq); |
1317 | 0 | } else { |
1318 | 0 | status = smb2cli_close_recv(subreq); |
1319 | 0 | } |
1320 | 0 | TALLOC_FREE(subreq); |
1321 | 0 | if (!NT_STATUS_IS_OK(status)) { |
1322 | 0 | tevent_req_error(req, EPIPE); |
1323 | 0 | return; |
1324 | 0 | } |
1325 | | |
1326 | 0 | cli_nps->conn = NULL; |
1327 | 0 | cli_nps->session = NULL; |
1328 | 0 | cli_nps->tcon = NULL; |
1329 | |
|
1330 | 0 | tevent_req_done(req); |
1331 | 0 | } |
1332 | | |
1333 | | static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq); |
1334 | | |
1335 | | static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req, |
1336 | | enum tevent_req_state req_state) |
1337 | 0 | { |
1338 | 0 | struct tstream_smbXcli_np_disconnect_state *state = |
1339 | 0 | tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state); |
1340 | 0 | struct tstream_smbXcli_np *cli_nps = NULL; |
1341 | |
|
1342 | 0 | if (state->subreq == NULL) { |
1343 | 0 | return; |
1344 | 0 | } |
1345 | | |
1346 | 0 | cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np); |
1347 | |
|
1348 | 0 | if (cli_nps->tcon == NULL) { |
1349 | 0 | return; |
1350 | 0 | } |
1351 | | |
1352 | | /* |
1353 | | * We're no longer interested in the result |
1354 | | * any more, but need to make sure that the close |
1355 | | * request arrives at the server if the smb connection, |
1356 | | * session and tcon are still alive. |
1357 | | * |
1358 | | * We move the low level request to the tcon, |
1359 | | * which means that it stays as long as the tcon |
1360 | | * is available. |
1361 | | */ |
1362 | 0 | talloc_steal(cli_nps->tcon, state->subreq); |
1363 | 0 | tevent_req_set_callback(state->subreq, |
1364 | 0 | tstream_smbXcli_np_disconnect_free, |
1365 | 0 | NULL); |
1366 | 0 | state->subreq = NULL; |
1367 | |
|
1368 | 0 | cli_nps->conn = NULL; |
1369 | 0 | cli_nps->session = NULL; |
1370 | 0 | cli_nps->tcon = NULL; |
1371 | 0 | } |
1372 | | |
1373 | | static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq) |
1374 | 0 | { |
1375 | 0 | TALLOC_FREE(subreq); |
1376 | 0 | } |
1377 | | |
1378 | | static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req, |
1379 | | int *perrno) |
1380 | 0 | { |
1381 | 0 | int ret; |
1382 | |
|
1383 | 0 | ret = tsocket_simple_int_recv(req, perrno); |
1384 | |
|
1385 | 0 | tevent_req_received(req); |
1386 | 0 | return ret; |
1387 | 0 | } |
1388 | | |
1389 | | static const struct tstream_context_ops tstream_smbXcli_np_ops = { |
1390 | | .name = "smbXcli_np", |
1391 | | |
1392 | | .pending_bytes = tstream_smbXcli_np_pending_bytes, |
1393 | | |
1394 | | .readv_send = tstream_smbXcli_np_readv_send, |
1395 | | .readv_recv = tstream_smbXcli_np_readv_recv, |
1396 | | |
1397 | | .writev_send = tstream_smbXcli_np_writev_send, |
1398 | | .writev_recv = tstream_smbXcli_np_writev_recv, |
1399 | | |
1400 | | .disconnect_send = tstream_smbXcli_np_disconnect_send, |
1401 | | .disconnect_recv = tstream_smbXcli_np_disconnect_recv, |
1402 | | }; |