Coverage Report

Created: 2026-04-01 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/libcli/smb/smb2cli_tcon.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   smb2 lib
4
   Copyright (C) Volker Lendecke 2011
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 "../libcli/smb/smb_common.h"
24
#include "../libcli/smb/smbXcli_base.h"
25
26
struct smb2cli_raw_tcon_state {
27
  struct smbXcli_session *session;
28
  struct smbXcli_tcon *tcon;
29
  uint8_t fixed[8];
30
  uint8_t dyn_pad[1];
31
};
32
33
static void smb2cli_raw_tcon_done(struct tevent_req *subreq);
34
35
struct tevent_req *smb2cli_raw_tcon_send(TALLOC_CTX *mem_ctx,
36
           struct tevent_context *ev,
37
           struct smbXcli_conn *conn,
38
           uint32_t additional_flags,
39
           uint32_t clear_flags,
40
           uint32_t timeout_msec,
41
           struct smbXcli_session *session,
42
           struct smbXcli_tcon *tcon,
43
           uint16_t tcon_flags,
44
           const char *unc)
45
0
{
46
0
  struct tevent_req *req = NULL;
47
0
  struct smb2cli_raw_tcon_state *state = NULL;
48
0
  struct tevent_req *subreq = NULL;
49
0
  uint8_t *fixed = NULL;
50
0
  uint8_t *dyn = NULL;
51
0
  size_t dyn_len;
52
53
0
  req = tevent_req_create(mem_ctx, &state,
54
0
        struct smb2cli_raw_tcon_state);
55
0
  if (req == NULL) {
56
0
    return NULL;
57
0
  }
58
0
  state->session = session;
59
0
  state->tcon = tcon;
60
61
0
  if (!convert_string_talloc(state, CH_UNIX, CH_UTF16,
62
0
           unc, strlen(unc),
63
0
           &dyn, &dyn_len)) {
64
0
    tevent_req_oom(req);
65
0
    return tevent_req_post(req, ev);
66
0
  }
67
68
0
  if (strlen(unc) == 0) {
69
0
    TALLOC_FREE(dyn);
70
0
    dyn_len = 0;
71
0
  }
72
73
0
  fixed = state->fixed;
74
0
  SSVAL(fixed, 0, 9);
75
0
  if (smbXcli_conn_protocol(conn) >= PROTOCOL_SMB3_11) {
76
0
    SSVAL(fixed, 2, tcon_flags);
77
0
  } else {
78
0
    SSVAL(fixed, 2, 0); /* Reserved */
79
0
  }
80
0
  SSVAL(fixed, 4, SMB2_HDR_BODY + 8);
81
0
  SSVAL(fixed, 6, dyn_len);
82
83
0
  if (dyn_len == 0) {
84
0
    dyn = state->dyn_pad;
85
0
    dyn_len = sizeof(state->dyn_pad);
86
0
  }
87
88
0
  subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TCON,
89
0
          additional_flags, clear_flags,
90
0
          timeout_msec,
91
0
          NULL, /* tcon */
92
0
          session,
93
0
          state->fixed, sizeof(state->fixed),
94
0
          dyn, dyn_len,
95
0
          0); /* max_dyn_len */
96
0
  if (tevent_req_nomem(subreq, req)) {
97
0
    return tevent_req_post(req, ev);
98
0
  }
99
0
  tevent_req_set_callback(subreq, smb2cli_raw_tcon_done, req);
100
101
0
  return req;
102
0
}
103
104
static void smb2cli_raw_tcon_done(struct tevent_req *subreq)
105
0
{
106
0
  struct tevent_req *req = tevent_req_callback_data(
107
0
    subreq, struct tevent_req);
108
0
  struct smb2cli_raw_tcon_state *state = tevent_req_data(
109
0
    req, struct smb2cli_raw_tcon_state);
110
0
  NTSTATUS status;
111
0
  struct iovec *iov;
112
0
  uint8_t *body;
113
0
  uint32_t tcon_id;
114
0
  uint8_t share_type;
115
0
  uint32_t share_flags;
116
0
  uint32_t share_capabilities;
117
0
  uint32_t maximal_access;
118
0
  static const struct smb2cli_req_expected_response expected[] = {
119
0
  {
120
0
    .status = NT_STATUS_OK,
121
0
    .body_size = 0x10
122
0
  }
123
0
  };
124
125
0
  status = smb2cli_req_recv(subreq, state, &iov,
126
0
          expected, ARRAY_SIZE(expected));
127
0
  TALLOC_FREE(subreq);
128
0
  if (!NT_STATUS_IS_OK(status)) {
129
0
    tevent_req_nterror(req, status);
130
0
    return;
131
0
  }
132
133
0
  tcon_id = IVAL(iov[0].iov_base, SMB2_HDR_TID);
134
135
0
  body = (uint8_t *)iov[1].iov_base;
136
0
  share_type    = CVAL(body, 0x02);
137
0
  share_flags   = IVAL(body, 0x04);
138
0
  share_capabilities  = IVAL(body, 0x08);
139
0
  maximal_access    = IVAL(body, 0x0C);
140
141
0
  smb2cli_tcon_set_values(state->tcon,
142
0
        state->session,
143
0
        tcon_id,
144
0
        share_type,
145
0
        share_flags,
146
0
        share_capabilities,
147
0
        maximal_access);
148
149
0
  tevent_req_done(req);
150
0
}
151
152
NTSTATUS smb2cli_raw_tcon_recv(struct tevent_req *req)
153
0
{
154
0
  return tevent_req_simple_recv_ntstatus(req);
155
0
}
156
157
NTSTATUS smb2cli_raw_tcon(struct smbXcli_conn *conn,
158
        uint32_t additional_flags,
159
        uint32_t clear_flags,
160
        uint32_t timeout_msec,
161
        struct smbXcli_session *session,
162
        struct smbXcli_tcon *tcon,
163
        uint16_t tcon_flags,
164
        const char *unc)
165
0
{
166
0
  TALLOC_CTX *frame = talloc_stackframe();
167
0
  struct tevent_context *ev;
168
0
  struct tevent_req *req;
169
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
170
171
0
  if (smbXcli_conn_has_async_calls(conn)) {
172
    /*
173
     * Can't use sync call while an async call is in flight
174
     */
175
0
    status = NT_STATUS_INVALID_PARAMETER;
176
0
    goto fail;
177
0
  }
178
0
  ev = samba_tevent_context_init(frame);
179
0
  if (ev == NULL) {
180
0
    goto fail;
181
0
  }
182
0
  req = smb2cli_raw_tcon_send(frame, ev, conn,
183
0
            additional_flags, clear_flags,
184
0
            timeout_msec, session, tcon,
185
0
            tcon_flags, unc);
186
0
  if (req == NULL) {
187
0
    goto fail;
188
0
  }
189
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
190
0
    goto fail;
191
0
  }
192
0
  status = smb2cli_raw_tcon_recv(req);
193
0
 fail:
194
0
  TALLOC_FREE(frame);
195
0
  return status;
196
0
}
197
198
struct smb2cli_tcon_state {
199
  struct tevent_context *ev;
200
  struct smbXcli_conn *conn;
201
  uint32_t timeout_msec;
202
  struct smbXcli_session *session;
203
  struct smbXcli_tcon *tcon;
204
  uint8_t fixed[8];
205
  uint8_t dyn_pad[1];
206
};
207
208
static void smb2cli_tcon_done(struct tevent_req *subreq);
209
210
struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx,
211
             struct tevent_context *ev,
212
             struct smbXcli_conn *conn,
213
             uint32_t timeout_msec,
214
             struct smbXcli_session *session,
215
             struct smbXcli_tcon *tcon,
216
             uint16_t flags,
217
             const char *unc)
218
0
{
219
0
  struct tevent_req *req, *subreq;
220
0
  struct smb2cli_tcon_state *state;
221
0
  uint32_t additional_flags = 0;
222
0
  uint32_t clear_flags = 0;
223
224
0
  req = tevent_req_create(mem_ctx, &state, struct smb2cli_tcon_state);
225
0
  if (req == NULL) {
226
0
    return NULL;
227
0
  }
228
0
  state->ev = ev;
229
0
  state->conn = conn;
230
0
  state->timeout_msec = timeout_msec;
231
0
  state->session = session;
232
0
  state->tcon = tcon;
233
234
0
  if (smbXcli_session_is_authenticated(state->session)) {
235
0
    additional_flags |= SMB2_HDR_FLAG_SIGNED;
236
0
  }
237
238
0
  subreq = smb2cli_raw_tcon_send(state,
239
0
               state->ev,
240
0
               state->conn,
241
0
               additional_flags,
242
0
               clear_flags,
243
0
               state->timeout_msec,
244
0
               state->session,
245
0
               state->tcon,
246
0
               flags,
247
0
               unc);
248
0
  if (tevent_req_nomem(subreq, req)) {
249
0
    return tevent_req_post(req, ev);
250
0
  }
251
0
  tevent_req_set_callback(subreq, smb2cli_tcon_done, req);
252
253
0
  return req;
254
0
}
255
256
static void smb2cli_tcon_validate(struct tevent_req *subreq);
257
258
static void smb2cli_tcon_done(struct tevent_req *subreq)
259
0
{
260
0
  struct tevent_req *req = tevent_req_callback_data(
261
0
    subreq, struct tevent_req);
262
0
  struct smb2cli_tcon_state *state = tevent_req_data(
263
0
    req, struct smb2cli_tcon_state);
264
0
  NTSTATUS status;
265
266
0
  status = smb2cli_raw_tcon_recv(subreq);
267
0
  TALLOC_FREE(subreq);
268
0
  if (tevent_req_nterror(req, status)) {
269
0
    return;
270
0
  }
271
272
0
  if (!smbXcli_session_is_authenticated(state->session)) {
273
0
    tevent_req_done(req);
274
0
    return;
275
0
  }
276
277
0
  if (smbXcli_conn_protocol(state->conn) >= PROTOCOL_SMB3_11) {
278
0
    tevent_req_done(req);
279
0
    return;
280
0
  }
281
282
0
  subreq = smb2cli_validate_negotiate_info_send(state, state->ev,
283
0
                  state->conn,
284
0
                  state->timeout_msec,
285
0
                  state->session,
286
0
                  state->tcon);
287
0
  if (tevent_req_nomem(subreq, req)) {
288
0
    return;
289
0
  }
290
0
  tevent_req_set_callback(subreq, smb2cli_tcon_validate, req);
291
0
}
292
293
static void smb2cli_tcon_validate(struct tevent_req *subreq)
294
0
{
295
0
  struct tevent_req *req = tevent_req_callback_data(
296
0
    subreq, struct tevent_req);
297
0
  struct smb2cli_tcon_state *state = tevent_req_data(
298
0
    req, struct smb2cli_tcon_state);
299
0
  NTSTATUS status;
300
301
0
  status = smb2cli_validate_negotiate_info_recv(subreq);
302
0
  TALLOC_FREE(subreq);
303
0
  if (!NT_STATUS_IS_OK(status)) {
304
0
    smb2cli_tcon_set_values(state->tcon, NULL,
305
0
          UINT32_MAX, 0, 0, 0, 0);
306
0
    tevent_req_nterror(req, status);
307
0
    return;
308
0
  }
309
310
0
  tevent_req_done(req);
311
0
}
312
313
NTSTATUS smb2cli_tcon_recv(struct tevent_req *req)
314
0
{
315
0
  return tevent_req_simple_recv_ntstatus(req);
316
0
}
317
318
NTSTATUS smb2cli_tcon(struct smbXcli_conn *conn,
319
          uint32_t timeout_msec,
320
          struct smbXcli_session *session,
321
          struct smbXcli_tcon *tcon,
322
          uint16_t flags,
323
          const char *unc)
324
0
{
325
0
  TALLOC_CTX *frame = talloc_stackframe();
326
0
  struct tevent_context *ev;
327
0
  struct tevent_req *req;
328
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
329
330
0
  if (smbXcli_conn_has_async_calls(conn)) {
331
    /*
332
     * Can't use sync call while an async call is in flight
333
     */
334
0
    status = NT_STATUS_INVALID_PARAMETER;
335
0
    goto fail;
336
0
  }
337
0
  ev = samba_tevent_context_init(frame);
338
0
  if (ev == NULL) {
339
0
    goto fail;
340
0
  }
341
0
  req = smb2cli_tcon_send(frame, ev, conn,
342
0
        timeout_msec, session, tcon,
343
0
        flags, unc);
344
0
  if (req == NULL) {
345
0
    goto fail;
346
0
  }
347
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
348
0
    goto fail;
349
0
  }
350
0
  status = smb2cli_tcon_recv(req);
351
0
 fail:
352
0
  TALLOC_FREE(frame);
353
0
  return status;
354
0
}
355
356
struct smb2cli_tdis_state {
357
  struct smbXcli_tcon *tcon;
358
  uint8_t fixed[4];
359
};
360
361
static void smb2cli_tdis_done(struct tevent_req *subreq);
362
363
struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx,
364
             struct tevent_context *ev,
365
             struct smbXcli_conn *conn,
366
             uint32_t timeout_msec,
367
             struct smbXcli_session *session,
368
             struct smbXcli_tcon *tcon)
369
0
{
370
0
  struct tevent_req *req, *subreq;
371
0
  struct smb2cli_tdis_state *state;
372
373
0
  req = tevent_req_create(mem_ctx, &state,
374
0
        struct smb2cli_tdis_state);
375
0
  if (req == NULL) {
376
0
    return NULL;
377
0
  }
378
0
  state->tcon = tcon;
379
380
0
  SSVAL(state->fixed, 0, 4);
381
382
0
  subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_TDIS,
383
0
          0, 0, /* flags */
384
0
          timeout_msec,
385
0
          tcon, session,
386
0
          state->fixed, sizeof(state->fixed),
387
0
          NULL, 0, /* dyn* */
388
0
          0); /* max_dyn_len */
389
0
  if (tevent_req_nomem(subreq, req)) {
390
0
    return tevent_req_post(req, ev);
391
0
  }
392
0
  tevent_req_set_callback(subreq, smb2cli_tdis_done, req);
393
0
  return req;
394
0
}
395
396
static void smb2cli_tdis_done(struct tevent_req *subreq)
397
0
{
398
0
  struct tevent_req *req =
399
0
    tevent_req_callback_data(subreq,
400
0
    struct tevent_req);
401
0
  struct smb2cli_tdis_state *state =
402
0
    tevent_req_data(req,
403
0
    struct smb2cli_tdis_state);
404
0
  NTSTATUS status;
405
0
  static const struct smb2cli_req_expected_response expected[] = {
406
0
  {
407
0
    .status = NT_STATUS_OK,
408
0
    .body_size = 0x04
409
0
  }
410
0
  };
411
412
0
  status = smb2cli_req_recv(subreq, NULL, NULL,
413
0
          expected, ARRAY_SIZE(expected));
414
0
  TALLOC_FREE(subreq);
415
0
  if (tevent_req_nterror(req, status)) {
416
0
    return;
417
0
  }
418
0
  smb2cli_tcon_set_values(state->tcon, NULL,
419
0
        UINT32_MAX, 0, 0, 0, 0);
420
0
  tevent_req_done(req);
421
0
}
422
423
NTSTATUS smb2cli_tdis_recv(struct tevent_req *req)
424
0
{
425
0
  return tevent_req_simple_recv_ntstatus(req);
426
0
}
427
428
NTSTATUS smb2cli_tdis(struct smbXcli_conn *conn,
429
          uint32_t timeout_msec,
430
          struct smbXcli_session *session,
431
          struct smbXcli_tcon *tcon)
432
0
{
433
0
  TALLOC_CTX *frame = talloc_stackframe();
434
0
  struct tevent_context *ev;
435
0
  struct tevent_req *req;
436
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
437
438
0
  if (smbXcli_conn_has_async_calls(conn)) {
439
    /*
440
     * Can't use sync call while an async call is in flight
441
     */
442
0
    status = NT_STATUS_INVALID_PARAMETER;
443
0
    goto fail;
444
0
  }
445
0
  ev = samba_tevent_context_init(frame);
446
0
  if (ev == NULL) {
447
0
    goto fail;
448
0
  }
449
0
  req = smb2cli_tdis_send(frame, ev, conn,
450
0
        timeout_msec, session, tcon);
451
0
  if (req == NULL) {
452
0
    goto fail;
453
0
  }
454
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
455
0
    goto fail;
456
0
  }
457
0
  status = smb2cli_tdis_recv(req);
458
0
 fail:
459
  TALLOC_FREE(frame);
460
0
  return status;
461
0
}