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