Coverage Report

Created: 2025-12-31 06:20

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