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