tstream: Fix CID 1167981 Unchecked return value
[samba.git] / libcli / smb / tstream_smbXcli_np.c
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 static int tstream_smbXcli_np_destructor(struct tstream_smbXcli_np *cli_nps)
80 {
81         NTSTATUS status;
82
83         if (cli_nps->conn_ref != NULL) {
84                 cli_nps->conn_ref->cli_nps = NULL;
85                 TALLOC_FREE(cli_nps->conn_ref);
86         }
87
88         if (cli_nps->session_ref != NULL) {
89                 cli_nps->session_ref->cli_nps = NULL;
90                 TALLOC_FREE(cli_nps->session_ref);
91         }
92
93         if (cli_nps->tcon_ref != NULL) {
94                 cli_nps->tcon_ref->cli_nps = NULL;
95                 TALLOC_FREE(cli_nps->tcon_ref);
96         }
97
98         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
99                 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         cli_nps->timeout = MIN(cli_nps->timeout, 1000);
118
119         if (cli_nps->is_smb1) {
120                 status = smb1cli_close(cli_nps->conn,
121                                        cli_nps->timeout,
122                                        cli_nps->pid,
123                                        cli_nps->tcon,
124                                        cli_nps->session,
125                                        cli_nps->fnum, UINT32_MAX);
126         } else {
127                 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         if (!NT_STATUS_IS_OK(status)) {
136                 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         return 0;
144 }
145
146 static int tstream_smbXcli_np_ref_destructor(struct tstream_smbXcli_np_ref *ref)
147 {
148         if (ref->cli_nps == NULL) {
149                 return 0;
150         }
151
152         if (ref->cli_nps->conn == NULL) {
153                 return 0;
154         }
155
156         ref->cli_nps->conn = NULL;
157         ref->cli_nps->session = NULL;
158         ref->cli_nps->tcon = NULL;
159
160         TALLOC_FREE(ref->cli_nps->conn_ref);
161         TALLOC_FREE(ref->cli_nps->session_ref);
162         TALLOC_FREE(ref->cli_nps->tcon_ref);
163
164         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 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         req = tevent_req_create(mem_ctx, &state,
203                                 struct tstream_smbXcli_np_open_state);
204         if (!req) {
205                 return NULL;
206         }
207         state->conn = conn;
208         state->tcon = tcon;
209         state->session = session;
210         state->pid = pid;
211         state->timeout = timeout;
212
213         state->npipe = talloc_strdup(state, npipe);
214         if (tevent_req_nomem(state->npipe, req)) {
215                 return tevent_req_post(req, ev);
216         }
217
218         if (smbXcli_conn_protocol(conn) < PROTOCOL_SMB2_02) {
219                 state->is_smb1 = true;
220         }
221
222         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                 smb1_npipe = talloc_asprintf(state, "\\%s", state->npipe);
231                 if (tevent_req_nomem(smb1_npipe, req)) {
232                         return tevent_req_post(req, ev);
233                 }
234                 subreq = smb1cli_ntcreatex_send(state, ev, state->conn,
235                                                 state->timeout,
236                                                 state->pid,
237                                                 state->tcon,
238                                                 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                 subreq = smb2cli_create_send(state, ev, state->conn,
252                                              state->timeout, state->session,
253                                              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         if (tevent_req_nomem(subreq, req)) {
265                 return tevent_req_post(req, ev);
266         }
267         tevent_req_set_callback(subreq, tstream_smbXcli_np_open_done, req);
268
269         return req;
270 }
271
272 static void tstream_smbXcli_np_open_done(struct tevent_req *subreq)
273 {
274         struct tevent_req *req =
275                 tevent_req_callback_data(subreq, struct tevent_req);
276         struct tstream_smbXcli_np_open_state *state =
277                 tevent_req_data(req, struct tstream_smbXcli_np_open_state);
278         NTSTATUS status;
279
280         if (state->is_smb1) {
281                 status = smb1cli_ntcreatex_recv(subreq, &state->fnum);
282         } else {
283                 status = smb2cli_create_recv(subreq,
284                                              &state->fid_persistent,
285                                              &state->fid_volatile,
286                                              NULL, NULL, NULL);
287         }
288         TALLOC_FREE(subreq);
289         if (!NT_STATUS_IS_OK(status)) {
290                 tevent_req_nterror(req, status);
291                 return;
292         }
293
294         tevent_req_done(req);
295 }
296
297 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         struct tstream_smbXcli_np_open_state *state =
303                 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         if (tevent_req_is_nterror(req, &status)) {
309                 tevent_req_received(req);
310                 return status;
311         }
312
313         stream = tstream_context_create(mem_ctx,
314                                         &tstream_smbXcli_np_ops,
315                                         &cli_nps,
316                                         struct tstream_smbXcli_np,
317                                         location);
318         if (!stream) {
319                 tevent_req_received(req);
320                 return NT_STATUS_NO_MEMORY;
321         }
322         ZERO_STRUCTP(cli_nps);
323
324         cli_nps->conn_ref = talloc_zero(state->conn,
325                                         struct tstream_smbXcli_np_ref);
326         if (cli_nps->conn_ref == NULL) {
327                 TALLOC_FREE(cli_nps);
328                 tevent_req_received(req);
329                 return NT_STATUS_NO_MEMORY;
330         }
331         cli_nps->conn_ref->cli_nps = cli_nps;
332
333         cli_nps->session_ref = talloc_zero(state->session,
334                                         struct tstream_smbXcli_np_ref);
335         if (cli_nps->session_ref == NULL) {
336                 TALLOC_FREE(cli_nps);
337                 tevent_req_received(req);
338                 return NT_STATUS_NO_MEMORY;
339         }
340         cli_nps->session_ref->cli_nps = cli_nps;
341
342         cli_nps->tcon_ref = talloc_zero(state->tcon,
343                                         struct tstream_smbXcli_np_ref);
344         if (cli_nps->tcon_ref == NULL) {
345                 TALLOC_FREE(cli_nps);
346                 tevent_req_received(req);
347                 return NT_STATUS_NO_MEMORY;
348         }
349         cli_nps->tcon_ref->cli_nps = cli_nps;
350
351         cli_nps->conn = state->conn;
352         cli_nps->session = state->session;
353         cli_nps->tcon = state->tcon;
354         cli_nps->pid  = state->pid;
355         cli_nps->timeout = state->timeout;
356         cli_nps->npipe = talloc_move(cli_nps, &state->npipe);
357         cli_nps->is_smb1 = state->is_smb1;
358         cli_nps->fnum = state->fnum;
359         cli_nps->fid_persistent = state->fid_persistent;
360         cli_nps->fid_volatile = state->fid_volatile;
361
362         talloc_set_destructor(cli_nps, tstream_smbXcli_np_destructor);
363         talloc_set_destructor(cli_nps->conn_ref,
364                               tstream_smbXcli_np_ref_destructor);
365         talloc_set_destructor(cli_nps->session_ref,
366                               tstream_smbXcli_np_ref_destructor);
367         talloc_set_destructor(cli_nps->tcon_ref,
368                               tstream_smbXcli_np_ref_destructor);
369
370         cli_nps->trans.active = false;
371         cli_nps->trans.read_req = NULL;
372         cli_nps->trans.write_req = NULL;
373         SSVAL(cli_nps->trans.setup+0, 0, TRANSACT_DCERPCCMD);
374         SSVAL(cli_nps->trans.setup+1, 0, cli_nps->fnum);
375
376         *_stream = stream;
377         tevent_req_received(req);
378         return NT_STATUS_OK;
379 }
380
381 static ssize_t tstream_smbXcli_np_pending_bytes(struct tstream_context *stream)
382 {
383         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
384                                          struct tstream_smbXcli_np);
385
386         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
387                 errno = ENOTCONN;
388                 return -1;
389         }
390
391         return cli_nps->read.left;
392 }
393
394 bool tstream_is_smbXcli_np(struct tstream_context *stream)
395 {
396         struct tstream_smbXcli_np *cli_nps =
397                 talloc_get_type(_tstream_context_data(stream),
398                 struct tstream_smbXcli_np);
399
400         if (!cli_nps) {
401                 return false;
402         }
403
404         return true;
405 }
406
407 NTSTATUS tstream_smbXcli_np_use_trans(struct tstream_context *stream)
408 {
409         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
410                                          struct tstream_smbXcli_np);
411
412         if (cli_nps->trans.read_req) {
413                 return NT_STATUS_PIPE_BUSY;
414         }
415
416         if (cli_nps->trans.write_req) {
417                 return NT_STATUS_PIPE_BUSY;
418         }
419
420         if (cli_nps->trans.active) {
421                 return NT_STATUS_PIPE_BUSY;
422         }
423
424         cli_nps->trans.active = true;
425
426         return NT_STATUS_OK;
427 }
428
429 unsigned int tstream_smbXcli_np_set_timeout(struct tstream_context *stream,
430                                             unsigned int timeout)
431 {
432         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
433                                          struct tstream_smbXcli_np);
434         unsigned int old_timeout = cli_nps->timeout;
435
436         cli_nps->timeout = timeout;
437         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 static int tstream_smbXcli_np_writev_state_destructor(struct tstream_smbXcli_np_writev_state *state)
456 {
457         struct tstream_smbXcli_np *cli_nps =
458                 tstream_context_data(state->stream,
459                 struct tstream_smbXcli_np);
460
461         cli_nps->trans.write_req = NULL;
462
463         return 0;
464 }
465
466 static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req);
467
468 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         struct tstream_smbXcli_np *cli_nps = tstream_context_data(stream,
477                                          struct tstream_smbXcli_np);
478
479         req = tevent_req_create(mem_ctx, &state,
480                                 struct tstream_smbXcli_np_writev_state);
481         if (!req) {
482                 return NULL;
483         }
484         state->stream = stream;
485         state->ev = ev;
486         state->ret = 0;
487
488         talloc_set_destructor(state, tstream_smbXcli_np_writev_state_destructor);
489
490         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
491                 tevent_req_error(req, ENOTCONN);
492                 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         state->vector = talloc_array(state, struct iovec, count);
499         if (tevent_req_nomem(state->vector, req)) {
500                 return tevent_req_post(req, ev);
501         }
502         memcpy(state->vector, vector, sizeof(struct iovec) * count);
503         state->count = count;
504
505         tstream_smbXcli_np_writev_write_next(req);
506         if (!tevent_req_is_in_progress(req)) {
507                 return tevent_req_post(req, ev);
508         }
509
510         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 static void tstream_smbXcli_np_writev_write_next(struct tevent_req *req)
517 {
518         struct tstream_smbXcli_np_writev_state *state =
519                 tevent_req_data(req,
520                 struct tstream_smbXcli_np_writev_state);
521         struct tstream_smbXcli_np *cli_nps =
522                 tstream_context_data(state->stream,
523                 struct tstream_smbXcli_np);
524         struct tevent_req *subreq;
525         size_t i;
526         size_t left = 0;
527
528         for (i=0; i < state->count; i++) {
529                 left += state->vector[i].iov_len;
530         }
531
532         if (left == 0) {
533                 TALLOC_FREE(cli_nps->write.buf);
534                 tevent_req_done(req);
535                 return;
536         }
537
538         cli_nps->write.ofs = 0;
539         cli_nps->write.left = MIN(left, TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
540         cli_nps->write.buf = talloc_realloc(cli_nps, cli_nps->write.buf,
541                                             uint8_t, cli_nps->write.left);
542         if (tevent_req_nomem(cli_nps->write.buf, req)) {
543                 return;
544         }
545
546         /*
547          * copy the pending buffer first
548          */
549         while (cli_nps->write.left > 0 && state->count > 0) {
550                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
551                 size_t len = MIN(cli_nps->write.left, state->vector[0].iov_len);
552
553                 memcpy(cli_nps->write.buf + cli_nps->write.ofs, base, len);
554
555                 base += len;
556                 state->vector[0].iov_base = base;
557                 state->vector[0].iov_len -= len;
558
559                 cli_nps->write.ofs += len;
560                 cli_nps->write.left -= len;
561
562                 if (state->vector[0].iov_len == 0) {
563                         state->vector += 1;
564                         state->count -= 1;
565                 }
566
567                 state->ret += len;
568         }
569
570         if (cli_nps->trans.active && state->count == 0) {
571                 cli_nps->trans.active = false;
572                 cli_nps->trans.write_req = req;
573                 return;
574         }
575
576         if (cli_nps->trans.read_req && state->count == 0) {
577                 cli_nps->trans.write_req = req;
578                 tstream_smbXcli_np_readv_trans_start(cli_nps->trans.read_req);
579                 return;
580         }
581
582         if (cli_nps->is_smb1) {
583                 subreq = smb1cli_writex_send(state, state->ev,
584                                              cli_nps->conn,
585                                              cli_nps->timeout,
586                                              cli_nps->pid,
587                                              cli_nps->tcon,
588                                              cli_nps->session,
589                                              cli_nps->fnum,
590                                              8, /* 8 means message mode. */
591                                              cli_nps->write.buf,
592                                              0, /* offset */
593                                              cli_nps->write.ofs); /* size */
594         } else {
595                 subreq = smb2cli_write_send(state, state->ev,
596                                             cli_nps->conn,
597                                             cli_nps->timeout,
598                                             cli_nps->session,
599                                             cli_nps->tcon,
600                                             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                                             cli_nps->write.buf);
607         }
608         if (tevent_req_nomem(subreq, req)) {
609                 return;
610         }
611         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 static void tstream_smbXcli_np_writev_write_done(struct tevent_req *subreq)
621 {
622         struct tevent_req *req =
623                 tevent_req_callback_data(subreq, struct tevent_req);
624         struct tstream_smbXcli_np_writev_state *state =
625                 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
626         struct tstream_smbXcli_np *cli_nps =
627                 tstream_context_data(state->stream,
628                 struct tstream_smbXcli_np);
629         uint32_t written;
630         NTSTATUS status;
631
632         if (cli_nps->is_smb1) {
633                 status = smb1cli_writex_recv(subreq, &written, NULL);
634         } else {
635                 status = smb2cli_write_recv(subreq, &written);
636         }
637         TALLOC_FREE(subreq);
638         if (!NT_STATUS_IS_OK(status)) {
639                 tstream_smbXcli_np_writev_disconnect_now(req, EPIPE, __location__);
640                 return;
641         }
642
643         if (written != cli_nps->write.ofs) {
644                 tstream_smbXcli_np_writev_disconnect_now(req, EIO, __location__);
645                 return;
646         }
647
648         tstream_smbXcli_np_writev_write_next(req);
649 }
650
651 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq);
652
653 static void tstream_smbXcli_np_writev_disconnect_now(struct tevent_req *req,
654                                                  int error,
655                                                  const char *location)
656 {
657         struct tstream_smbXcli_np_writev_state *state =
658                 tevent_req_data(req,
659                 struct tstream_smbXcli_np_writev_state);
660         struct tstream_smbXcli_np *cli_nps =
661                 tstream_context_data(state->stream,
662                 struct tstream_smbXcli_np);
663         struct tevent_req *subreq;
664
665         state->error.val = error;
666         state->error.location = location;
667
668         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
669                 /* return the original error */
670                 _tevent_req_error(req, state->error.val, state->error.location);
671                 return;
672         }
673
674         subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
675                                                     state->stream);
676         if (subreq == NULL) {
677                 /* return the original error */
678                 _tevent_req_error(req, state->error.val, state->error.location);
679                 return;
680         }
681         tevent_req_set_callback(subreq,
682                                 tstream_smbXcli_np_writev_disconnect_done,
683                                 req);
684 }
685
686 static void tstream_smbXcli_np_writev_disconnect_done(struct tevent_req *subreq)
687 {
688         struct tevent_req *req =
689                 tevent_req_callback_data(subreq, struct tevent_req);
690         struct tstream_smbXcli_np_writev_state *state =
691                 tevent_req_data(req, struct tstream_smbXcli_np_writev_state);
692         int error;
693
694         tstream_smbXcli_np_disconnect_recv(subreq, &error);
695         TALLOC_FREE(subreq);
696
697         /* return the original error */
698         _tevent_req_error(req, state->error.val, state->error.location);
699 }
700
701 static int tstream_smbXcli_np_writev_recv(struct tevent_req *req,
702                                       int *perrno)
703 {
704         struct tstream_smbXcli_np_writev_state *state =
705                 tevent_req_data(req,
706                 struct tstream_smbXcli_np_writev_state);
707         int ret;
708
709         ret = tsocket_simple_int_recv(req, perrno);
710         if (ret == 0) {
711                 ret = state->ret;
712         }
713
714         tevent_req_received(req);
715         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 static int tstream_smbXcli_np_readv_state_destructor(struct tstream_smbXcli_np_readv_state *state)
738 {
739         struct tstream_smbXcli_np *cli_nps =
740                 tstream_context_data(state->stream,
741                 struct tstream_smbXcli_np);
742
743         cli_nps->trans.read_req = NULL;
744
745         return 0;
746 }
747
748 static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req);
749
750 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         struct tstream_smbXcli_np *cli_nps =
759                 tstream_context_data(stream, struct tstream_smbXcli_np);
760
761         req = tevent_req_create(mem_ctx, &state,
762                                 struct tstream_smbXcli_np_readv_state);
763         if (!req) {
764                 return NULL;
765         }
766         state->stream = stream;
767         state->ev = ev;
768         state->ret = 0;
769
770         talloc_set_destructor(state, tstream_smbXcli_np_readv_state_destructor);
771
772         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
773                 tevent_req_error(req, ENOTCONN);
774                 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         state->vector = talloc_array(state, struct iovec, count);
781         if (tevent_req_nomem(state->vector, req)) {
782                 return tevent_req_post(req, ev);
783         }
784         memcpy(state->vector, vector, sizeof(struct iovec) * count);
785         state->count = count;
786
787         tstream_smbXcli_np_readv_read_next(req);
788         if (!tevent_req_is_in_progress(req)) {
789                 return tevent_req_post(req, ev);
790         }
791
792         return req;
793 }
794
795 static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq);
796
797 static void tstream_smbXcli_np_readv_read_next(struct tevent_req *req)
798 {
799         struct tstream_smbXcli_np_readv_state *state =
800                 tevent_req_data(req,
801                 struct tstream_smbXcli_np_readv_state);
802         struct tstream_smbXcli_np *cli_nps =
803                 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         while (cli_nps->read.left > 0 && state->count > 0) {
811                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
812                 size_t len = MIN(cli_nps->read.left, state->vector[0].iov_len);
813
814                 memcpy(base, cli_nps->read.buf + cli_nps->read.ofs, len);
815
816                 base += len;
817                 state->vector[0].iov_base = base;
818                 state->vector[0].iov_len -= len;
819
820                 cli_nps->read.ofs += len;
821                 cli_nps->read.left -= len;
822
823                 if (state->vector[0].iov_len == 0) {
824                         state->vector += 1;
825                         state->count -= 1;
826                 }
827
828                 state->ret += len;
829         }
830
831         if (cli_nps->read.left == 0) {
832                 TALLOC_FREE(cli_nps->read.buf);
833         }
834
835         if (state->count == 0) {
836                 tevent_req_done(req);
837                 return;
838         }
839
840         if (cli_nps->trans.active) {
841                 cli_nps->trans.active = false;
842                 cli_nps->trans.read_req = req;
843                 return;
844         }
845
846         if (cli_nps->trans.write_req) {
847                 cli_nps->trans.read_req = req;
848                 tstream_smbXcli_np_readv_trans_start(req);
849                 return;
850         }
851
852         if (cli_nps->is_smb1) {
853                 subreq = smb1cli_readx_send(state, state->ev,
854                                             cli_nps->conn,
855                                             cli_nps->timeout,
856                                             cli_nps->pid,
857                                             cli_nps->tcon,
858                                             cli_nps->session,
859                                             cli_nps->fnum,
860                                             0, /* offset */
861                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
862         } else {
863                 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         if (tevent_req_nomem(subreq, req)) {
876                 return;
877         }
878         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 static void tstream_smbXcli_np_readv_trans_start(struct tevent_req *req)
886 {
887         struct tstream_smbXcli_np_readv_state *state =
888                 tevent_req_data(req,
889                 struct tstream_smbXcli_np_readv_state);
890         struct tstream_smbXcli_np *cli_nps =
891                 tstream_context_data(state->stream,
892                 struct tstream_smbXcli_np);
893         struct tevent_req *subreq;
894
895         state->trans.im = tevent_create_immediate(state);
896         if (tevent_req_nomem(state->trans.im, req)) {
897                 return;
898         }
899
900         if (cli_nps->is_smb1) {
901                 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                                             cli_nps->pid,
907                                             cli_nps->tcon,
908                                             cli_nps->session,
909                                             "\\PIPE\\",
910                                             0, 0, 0,
911                                             cli_nps->trans.setup, 2,
912                                             0,
913                                             NULL, 0, 0,
914                                             cli_nps->write.buf,
915                                             cli_nps->write.ofs,
916                                             TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE);
917         } else {
918                 DATA_BLOB in_input_buffer = data_blob_null;
919                 DATA_BLOB in_output_buffer = data_blob_null;
920
921                 in_input_buffer = data_blob_const(cli_nps->write.buf,
922                                                   cli_nps->write.ofs);
923
924                 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         if (tevent_req_nomem(subreq, req)) {
940                 return;
941         }
942         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 static void tstream_smbXcli_np_readv_trans_done(struct tevent_req *subreq)
955 {
956         struct tevent_req *req =
957                 tevent_req_callback_data(subreq, struct tevent_req);
958         struct tstream_smbXcli_np_readv_state *state =
959                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
960         struct tstream_smbXcli_np *cli_nps =
961                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
962         uint8_t *rcvbuf;
963         uint32_t received;
964         NTSTATUS status;
965
966         if (cli_nps->is_smb1) {
967                 status = smb1cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
968                                             NULL, 0, NULL,
969                                             &rcvbuf, 0, &received);
970         } else {
971                 DATA_BLOB out_input_buffer = data_blob_null;
972                 DATA_BLOB out_output_buffer = data_blob_null;
973
974                 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                 rcvbuf = out_output_buffer.data;
980                 received = out_output_buffer.length;
981         }
982         TALLOC_FREE(subreq);
983         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                 status = NT_STATUS_OK;
992         }
993         if (!NT_STATUS_IS_OK(status)) {
994                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
995                 return;
996         }
997
998         if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
999                 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1000                 return;
1001         }
1002
1003         if (received == 0) {
1004                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1005                 return;
1006         }
1007
1008         cli_nps->read.ofs = 0;
1009         cli_nps->read.left = received;
1010         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1011         if (cli_nps->read.buf == NULL) {
1012                 TALLOC_FREE(subreq);
1013                 tevent_req_oom(req);
1014                 return;
1015         }
1016         memcpy(cli_nps->read.buf, rcvbuf, received);
1017
1018         if (cli_nps->trans.write_req == NULL) {
1019                 tstream_smbXcli_np_readv_read_next(req);
1020                 return;
1021         }
1022
1023         tevent_schedule_immediate(state->trans.im, state->ev,
1024                                   tstream_smbXcli_np_readv_trans_next, req);
1025
1026         tevent_req_done(cli_nps->trans.write_req);
1027 }
1028
1029 static void tstream_smbXcli_np_readv_trans_next(struct tevent_context *ctx,
1030                                             struct tevent_immediate *im,
1031                                             void *private_data)
1032 {
1033         struct tevent_req *req =
1034                 talloc_get_type_abort(private_data,
1035                 struct tevent_req);
1036
1037         tstream_smbXcli_np_readv_read_next(req);
1038 }
1039
1040 static void tstream_smbXcli_np_readv_read_done(struct tevent_req *subreq)
1041 {
1042         struct tevent_req *req =
1043                 tevent_req_callback_data(subreq, struct tevent_req);
1044         struct tstream_smbXcli_np_readv_state *state =
1045                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1046         struct tstream_smbXcli_np *cli_nps =
1047                 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         if (cli_nps->is_smb1) {
1058                 status = smb1cli_readx_recv(subreq, &received, &rcvbuf);
1059         } else {
1060                 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         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                 status = NT_STATUS_OK;
1075         }
1076         if (!NT_STATUS_IS_OK(status)) {
1077                 TALLOC_FREE(subreq);
1078                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1079                 return;
1080         }
1081
1082         if (received > TSTREAM_SMBXCLI_NP_MAX_BUF_SIZE) {
1083                 TALLOC_FREE(subreq);
1084                 tstream_smbXcli_np_readv_disconnect_now(req, EIO, __location__);
1085                 return;
1086         }
1087
1088         if (received == 0) {
1089                 TALLOC_FREE(subreq);
1090                 tstream_smbXcli_np_readv_disconnect_now(req, EPIPE, __location__);
1091                 return;
1092         }
1093
1094         cli_nps->read.ofs = 0;
1095         cli_nps->read.left = received;
1096         cli_nps->read.buf = talloc_array(cli_nps, uint8_t, received);
1097         if (cli_nps->read.buf == NULL) {
1098                 TALLOC_FREE(subreq);
1099                 tevent_req_oom(req);
1100                 return;
1101         }
1102         memcpy(cli_nps->read.buf, rcvbuf, received);
1103         TALLOC_FREE(subreq);
1104
1105         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 static void tstream_smbXcli_np_readv_disconnect_now(struct tevent_req *req,
1113                                                 int error,
1114                                                 const char *location)
1115 {
1116         struct tstream_smbXcli_np_readv_state *state =
1117                 tevent_req_data(req,
1118                 struct tstream_smbXcli_np_readv_state);
1119         struct tstream_smbXcli_np *cli_nps =
1120                 tstream_context_data(state->stream,
1121                 struct tstream_smbXcli_np);
1122         struct tevent_req *subreq;
1123
1124         state->error.val = error;
1125         state->error.location = location;
1126
1127         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1128                 /* return the original error */
1129                 tstream_smbXcli_np_readv_error(req);
1130                 return;
1131         }
1132
1133         subreq = tstream_smbXcli_np_disconnect_send(state, state->ev,
1134                                                     state->stream);
1135         if (subreq == NULL) {
1136                 /* return the original error */
1137                 tstream_smbXcli_np_readv_error(req);
1138                 return;
1139         }
1140         tevent_req_set_callback(subreq,
1141                                 tstream_smbXcli_np_readv_disconnect_done,
1142                                 req);
1143 }
1144
1145 static void tstream_smbXcli_np_readv_disconnect_done(struct tevent_req *subreq)
1146 {
1147         struct tevent_req *req =
1148                 tevent_req_callback_data(subreq, struct tevent_req);
1149         int error;
1150
1151         tstream_smbXcli_np_disconnect_recv(subreq, &error);
1152         TALLOC_FREE(subreq);
1153
1154         tstream_smbXcli_np_readv_error(req);
1155 }
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 static void tstream_smbXcli_np_readv_error(struct tevent_req *req)
1162 {
1163         struct tstream_smbXcli_np_readv_state *state =
1164                 tevent_req_data(req,
1165                 struct tstream_smbXcli_np_readv_state);
1166         struct tstream_smbXcli_np *cli_nps =
1167                 tstream_context_data(state->stream,
1168                 struct tstream_smbXcli_np);
1169
1170         if (cli_nps->trans.write_req == NULL) {
1171                 /* return the original error */
1172                 _tevent_req_error(req, state->error.val, state->error.location);
1173                 return;
1174         }
1175
1176         if (state->trans.im == NULL) {
1177                 /* return the original error */
1178                 _tevent_req_error(req, state->error.val, state->error.location);
1179                 return;
1180         }
1181
1182         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         _tevent_req_error(cli_nps->trans.write_req,
1187                           state->error.val, state->error.location);
1188 }
1189
1190 static void tstream_smbXcli_np_readv_error_trigger(struct tevent_context *ctx,
1191                                                    struct tevent_immediate *im,
1192                                                    void *private_data)
1193 {
1194         struct tevent_req *req =
1195                 talloc_get_type_abort(private_data,
1196                 struct tevent_req);
1197         struct tstream_smbXcli_np_readv_state *state =
1198                 tevent_req_data(req,
1199                 struct tstream_smbXcli_np_readv_state);
1200
1201         /* return the original error */
1202         _tevent_req_error(req, state->error.val, state->error.location);
1203 }
1204
1205 static int tstream_smbXcli_np_readv_recv(struct tevent_req *req,
1206                                          int *perrno)
1207 {
1208         struct tstream_smbXcli_np_readv_state *state =
1209                 tevent_req_data(req, struct tstream_smbXcli_np_readv_state);
1210         int ret;
1211
1212         ret = tsocket_simple_int_recv(req, perrno);
1213         if (ret == 0) {
1214                 ret = state->ret;
1215         }
1216
1217         tevent_req_received(req);
1218         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 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         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         req = tevent_req_create(mem_ctx, &state,
1241                                 struct tstream_smbXcli_np_disconnect_state);
1242         if (req == NULL) {
1243                 return NULL;
1244         }
1245
1246         state->stream = stream;
1247
1248         if (!smbXcli_conn_is_connected(cli_nps->conn)) {
1249                 tevent_req_error(req, ENOTCONN);
1250                 return tevent_req_post(req, ev);
1251         }
1252
1253         if (cli_nps->is_smb1) {
1254                 subreq = smb1cli_close_send(state, ev, cli_nps->conn,
1255                                             cli_nps->timeout,
1256                                             cli_nps->pid,
1257                                             cli_nps->tcon,
1258                                             cli_nps->session,
1259                                             cli_nps->fnum, UINT32_MAX);
1260         } else {
1261                 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         if (tevent_req_nomem(subreq, req)) {
1270                 return tevent_req_post(req, ev);
1271         }
1272         tevent_req_set_callback(subreq, tstream_smbXcli_np_disconnect_done, req);
1273         state->subreq = subreq;
1274
1275         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         cli_nps->conn = NULL;
1281
1282         return req;
1283 }
1284
1285 static void tstream_smbXcli_np_disconnect_done(struct tevent_req *subreq)
1286 {
1287         struct tevent_req *req = tevent_req_callback_data(subreq,
1288                                                           struct tevent_req);
1289         struct tstream_smbXcli_np_disconnect_state *state =
1290                 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1291         struct tstream_smbXcli_np *cli_nps =
1292                 tstream_context_data(state->stream, struct tstream_smbXcli_np);
1293         NTSTATUS status;
1294
1295         state->subreq = NULL;
1296
1297         if (cli_nps->is_smb1) {
1298                 status = smb1cli_close_recv(subreq);
1299         } else {
1300                 status = smb2cli_close_recv(subreq);
1301         }
1302         TALLOC_FREE(subreq);
1303         if (!NT_STATUS_IS_OK(status)) {
1304                 tevent_req_error(req, EPIPE);
1305                 return;
1306         }
1307
1308         cli_nps->conn = NULL;
1309         cli_nps->session = NULL;
1310         cli_nps->tcon = NULL;
1311
1312         tevent_req_done(req);
1313 }
1314
1315 static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq);
1316
1317 static void tstream_smbXcli_np_disconnect_cleanup(struct tevent_req *req,
1318                                         enum tevent_req_state req_state)
1319 {
1320         struct tstream_smbXcli_np_disconnect_state *state =
1321                 tevent_req_data(req, struct tstream_smbXcli_np_disconnect_state);
1322         struct tstream_smbXcli_np *cli_nps = NULL;
1323
1324         if (state->subreq == NULL) {
1325                 return;
1326         }
1327
1328         cli_nps = tstream_context_data(state->stream, struct tstream_smbXcli_np);
1329
1330         if (cli_nps->tcon == NULL) {
1331                 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         talloc_steal(cli_nps->tcon, state->subreq);
1345         tevent_req_set_callback(state->subreq,
1346                                 tstream_smbXcli_np_disconnect_free,
1347                                 NULL);
1348         state->subreq = NULL;
1349
1350         cli_nps->conn = NULL;
1351         cli_nps->session = NULL;
1352         cli_nps->tcon = NULL;
1353 }
1354
1355 static void tstream_smbXcli_np_disconnect_free(struct tevent_req *subreq)
1356 {
1357         TALLOC_FREE(subreq);
1358 }
1359
1360 static int tstream_smbXcli_np_disconnect_recv(struct tevent_req *req,
1361                                               int *perrno)
1362 {
1363         int ret;
1364
1365         ret = tsocket_simple_int_recv(req, perrno);
1366
1367         tevent_req_received(req);
1368         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 };