Coverage Report

Created: 2026-01-16 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/libsmb/clifile.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   client file operations
4
   Copyright (C) Andrew Tridgell 1994-1998
5
   Copyright (C) Jeremy Allison 2001-2009
6
7
   This program is free software; you can redistribute it and/or modify
8
   it under the terms of the GNU General Public License as published by
9
   the Free Software Foundation; either version 3 of the License, or
10
   (at your option) any later version.
11
12
   This program is distributed in the hope that it will be useful,
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
   GNU General Public License for more details.
16
17
   You should have received a copy of the GNU General Public License
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
*/
20
21
#include "includes.h"
22
#include "system/filesys.h"
23
#include "source3/include/client.h"
24
#include "source3/libsmb/proto.h"
25
#include "source3/libsmb/cli_smb2_fnum.h"
26
#include "../lib/util/tevent_ntstatus.h"
27
#include "async_smb.h"
28
#include "libsmb/clirap.h"
29
#include "trans2.h"
30
#include "ntioctl.h"
31
#include "libcli/security/security.h"
32
#include "../libcli/smb/smbXcli_base.h"
33
#include "libcli/smb/reparse.h"
34
35
struct cli_setpathinfo_state {
36
  uint16_t setup;
37
  uint8_t *param;
38
};
39
40
static void cli_setpathinfo_done(struct tevent_req *subreq);
41
42
struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
43
          struct tevent_context *ev,
44
          struct cli_state *cli,
45
          uint16_t level,
46
          const char *path,
47
          uint8_t *data,
48
          size_t data_len)
49
0
{
50
0
  struct tevent_req *req, *subreq;
51
0
  struct cli_setpathinfo_state *state;
52
0
  uint16_t additional_flags2 = 0;
53
0
  char *path_cp = NULL;
54
55
0
  req = tevent_req_create(mem_ctx, &state,
56
0
        struct cli_setpathinfo_state);
57
0
  if (req == NULL) {
58
0
    return NULL;
59
0
  }
60
61
  /* Setup setup word. */
62
0
  SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
63
64
  /* Setup param array. */
65
0
  state->param = talloc_zero_array(state, uint8_t, 6);
66
0
  if (tevent_req_nomem(state->param, req)) {
67
0
    return tevent_req_post(req, ev);
68
0
  }
69
0
  SSVAL(state->param, 0, level);
70
71
  /* Check for DFS. */
72
0
  path_cp = smb1_dfs_share_path(state, cli, path);
73
0
  if (tevent_req_nomem(path_cp, req)) {
74
0
    return tevent_req_post(req, ev);
75
0
  }
76
0
  state->param = trans2_bytes_push_str(state->param,
77
0
          smbXcli_conn_use_unicode(cli->conn),
78
0
          path_cp,
79
0
          strlen(path_cp)+1,
80
0
          NULL);
81
0
  if (tevent_req_nomem(state->param, req)) {
82
0
    return tevent_req_post(req, ev);
83
0
  }
84
85
0
  if (clistr_is_previous_version_path(path) &&
86
0
      !INFO_LEVEL_IS_UNIX(level)) {
87
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
88
0
  }
89
90
0
  subreq = cli_trans_send(
91
0
    state,      /* mem ctx. */
92
0
    ev,     /* event ctx. */
93
0
    cli,      /* cli_state. */
94
0
    additional_flags2,  /* additional_flags2 */
95
0
    SMBtrans2,   /* cmd. */
96
0
    NULL,     /* pipe name. */
97
0
    -1,     /* fid. */
98
0
    0,      /* function. */
99
0
    0,      /* flags. */
100
0
    &state->setup,    /* setup. */
101
0
    1,      /* num setup uint16_t words. */
102
0
    0,      /* max returned setup. */
103
0
    state->param,   /* param. */
104
0
    talloc_get_size(state->param),  /* num param. */
105
0
    2,      /* max returned param. */
106
0
    data,     /* data. */
107
0
    data_len,   /* num data. */
108
0
    0);     /* max returned data. */
109
110
0
  if (tevent_req_nomem(subreq, req)) {
111
0
    return tevent_req_post(req, ev);
112
0
  }
113
0
  tevent_req_set_callback(subreq, cli_setpathinfo_done, req);
114
0
  return req;
115
0
}
116
117
static void cli_setpathinfo_done(struct tevent_req *subreq)
118
0
{
119
0
  NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
120
0
           NULL, 0, NULL, NULL, 0, NULL);
121
0
  tevent_req_simple_finish_ntstatus(subreq, status);
122
0
}
123
124
NTSTATUS cli_setpathinfo_recv(struct tevent_req *req)
125
0
{
126
0
  return tevent_req_simple_recv_ntstatus(req);
127
0
}
128
129
NTSTATUS cli_setpathinfo(struct cli_state *cli,
130
       uint16_t level,
131
       const char *path,
132
       uint8_t *data,
133
       size_t data_len)
134
0
{
135
0
  TALLOC_CTX *frame = talloc_stackframe();
136
0
  struct tevent_context *ev;
137
0
  struct tevent_req *req;
138
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
139
140
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
141
    /*
142
     * Can't use sync call while an async call is in flight
143
     */
144
0
    status = NT_STATUS_INVALID_PARAMETER;
145
0
    goto fail;
146
0
  }
147
0
  ev = samba_tevent_context_init(frame);
148
0
  if (ev == NULL) {
149
0
    goto fail;
150
0
  }
151
0
  req = cli_setpathinfo_send(ev, ev, cli, level, path, data, data_len);
152
0
  if (req == NULL) {
153
0
    goto fail;
154
0
  }
155
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
156
0
    goto fail;
157
0
  }
158
0
  status = cli_setpathinfo_recv(req);
159
0
 fail:
160
0
  TALLOC_FREE(frame);
161
0
  return status;
162
0
}
163
164
struct cli_setfileinfo_state {
165
  uint16_t setup;
166
  uint8_t param[6];
167
};
168
169
static void cli_setfileinfo_done(struct tevent_req *subreq);
170
171
struct tevent_req *cli_setfileinfo_send(
172
  TALLOC_CTX *mem_ctx,
173
  struct tevent_context *ev,
174
  struct cli_state *cli,
175
  uint16_t fnum,
176
  uint16_t level,
177
  uint8_t *data,
178
  size_t data_len)
179
0
{
180
0
  struct tevent_req *req = NULL, *subreq = NULL;
181
0
  struct cli_setfileinfo_state *state = NULL;
182
183
0
  req = tevent_req_create(mem_ctx, &state, struct cli_setfileinfo_state);
184
0
  if (req == NULL) {
185
0
    return NULL;
186
0
  }
187
0
  PUSH_LE_U16(&state->setup, 0, TRANSACT2_SETFILEINFO);
188
189
0
  PUSH_LE_U16(state->param, 0, fnum);
190
0
  PUSH_LE_U16(state->param, 2, level);
191
192
0
  subreq = cli_trans_send(state,    /* mem ctx. */
193
0
        ev,   /* event ctx. */
194
0
        cli,    /* cli_state. */
195
0
        0,    /* additional_flags2 */
196
0
        SMBtrans2, /* cmd. */
197
0
        NULL,   /* pipe name. */
198
0
        -1,   /* fid. */
199
0
        0,    /* function. */
200
0
        0,    /* flags. */
201
0
        &state->setup,  /* setup. */
202
0
        1,    /* num setup uint16_t words. */
203
0
        0,    /* max returned setup. */
204
0
        state->param, /* param. */
205
0
        6,    /* num param. */
206
0
        2,    /* max returned param. */
207
0
        data,   /* data. */
208
0
        data_len, /* num data. */
209
0
        0);   /* max returned data. */
210
211
0
  if (tevent_req_nomem(subreq, req)) {
212
0
    return tevent_req_post(req, ev);
213
0
  }
214
0
  tevent_req_set_callback(subreq, cli_setfileinfo_done, req);
215
0
  return req;
216
0
}
217
218
static void cli_setfileinfo_done(struct tevent_req *subreq)
219
0
{
220
0
  NTSTATUS status = cli_trans_recv(
221
0
    subreq,   /* req */
222
0
    NULL,   /* mem_ctx */
223
0
    NULL,   /* recv_flags2 */
224
0
    NULL,   /* setup */
225
0
    0,    /* min_setup */
226
0
    NULL,   /* num_setup */
227
0
    NULL,   /* param */
228
0
    0,    /* min_param */
229
0
    NULL,   /* num_param */
230
0
    NULL,   /* data */
231
0
    0,    /* min_data */
232
0
    NULL);    /* num_data */
233
0
  tevent_req_simple_finish_ntstatus(subreq, status);
234
0
}
235
236
NTSTATUS cli_setfileinfo_recv(struct tevent_req *req)
237
0
{
238
0
  return tevent_req_simple_recv_ntstatus(req);
239
0
}
240
241
/****************************************************************************
242
 Hard/Symlink a file (UNIX extensions).
243
 Creates new name (sym)linked to link_target.
244
****************************************************************************/
245
246
struct cli_posix_link_internal_state {
247
  uint8_t *data;
248
};
249
250
static void cli_posix_link_internal_done(struct tevent_req *subreq);
251
252
static struct tevent_req *cli_posix_link_internal_send(TALLOC_CTX *mem_ctx,
253
          struct tevent_context *ev,
254
          struct cli_state *cli,
255
          uint16_t level,
256
          const char *link_target,
257
          const char *newname)
258
0
{
259
0
  struct tevent_req *req = NULL, *subreq = NULL;
260
0
  struct cli_posix_link_internal_state *state = NULL;
261
262
0
  req = tevent_req_create(mem_ctx, &state,
263
0
        struct cli_posix_link_internal_state);
264
0
  if (req == NULL) {
265
0
    return NULL;
266
0
  }
267
268
  /* Setup data array. */
269
0
  state->data = talloc_array(state, uint8_t, 0);
270
0
  if (tevent_req_nomem(state->data, req)) {
271
0
    return tevent_req_post(req, ev);
272
0
  }
273
0
  state->data = trans2_bytes_push_str(
274
0
    state->data, smbXcli_conn_use_unicode(cli->conn),
275
0
    link_target, strlen(link_target)+1, NULL);
276
277
0
  subreq = cli_setpathinfo_send(
278
0
    state, ev, cli, level, newname,
279
0
    state->data, talloc_get_size(state->data));
280
0
  if (tevent_req_nomem(subreq, req)) {
281
0
    return tevent_req_post(req, ev);
282
0
  }
283
0
  tevent_req_set_callback(subreq, cli_posix_link_internal_done, req);
284
0
  return req;
285
0
}
286
287
static void cli_posix_link_internal_done(struct tevent_req *subreq)
288
0
{
289
0
  NTSTATUS status = cli_setpathinfo_recv(subreq);
290
0
  tevent_req_simple_finish_ntstatus(subreq, status);
291
0
}
292
293
static NTSTATUS cli_posix_link_internal_recv(struct tevent_req *req)
294
0
{
295
0
  return tevent_req_simple_recv_ntstatus(req);
296
0
}
297
298
/****************************************************************************
299
 Symlink a file (UNIX extensions).
300
****************************************************************************/
301
302
struct cli_posix_symlink_state {
303
  uint8_t dummy;
304
};
305
306
static void cli_posix_symlink_done(struct tevent_req *subreq);
307
308
struct tevent_req *cli_posix_symlink_send(TALLOC_CTX *mem_ctx,
309
          struct tevent_context *ev,
310
          struct cli_state *cli,
311
          const char *link_target,
312
          const char *newname)
313
0
{
314
0
  struct tevent_req *req = NULL, *subreq = NULL;
315
0
  struct cli_posix_symlink_state *state = NULL;
316
317
0
  req = tevent_req_create(
318
0
    mem_ctx, &state, struct cli_posix_symlink_state);
319
0
  if (req == NULL) {
320
0
    return NULL;
321
0
  }
322
323
0
  subreq = cli_posix_link_internal_send(
324
0
    mem_ctx, ev, cli, SMB_SET_FILE_UNIX_LINK, link_target, newname);
325
0
  if (tevent_req_nomem(subreq, req)) {
326
0
    return tevent_req_post(req, ev);
327
0
  }
328
0
  tevent_req_set_callback(subreq, cli_posix_symlink_done, req);
329
0
  return req;
330
0
}
331
332
static void cli_posix_symlink_done(struct tevent_req *subreq)
333
0
{
334
0
  NTSTATUS status = cli_posix_link_internal_recv(subreq);
335
0
  tevent_req_simple_finish_ntstatus(subreq, status);
336
0
}
337
338
NTSTATUS cli_posix_symlink_recv(struct tevent_req *req)
339
0
{
340
0
  return tevent_req_simple_recv_ntstatus(req);
341
0
}
342
343
NTSTATUS cli_posix_symlink(struct cli_state *cli,
344
      const char *link_target,
345
      const char *newname)
346
0
{
347
0
  TALLOC_CTX *frame = talloc_stackframe();
348
0
  struct tevent_context *ev = NULL;
349
0
  struct tevent_req *req = NULL;
350
0
  NTSTATUS status = NT_STATUS_OK;
351
352
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
353
    /*
354
     * Can't use sync call while an async call is in flight
355
     */
356
0
    status = NT_STATUS_INVALID_PARAMETER;
357
0
    goto fail;
358
0
  }
359
360
0
  ev = samba_tevent_context_init(frame);
361
0
  if (ev == NULL) {
362
0
    status = NT_STATUS_NO_MEMORY;
363
0
    goto fail;
364
0
  }
365
366
0
  req = cli_posix_symlink_send(frame,
367
0
        ev,
368
0
        cli,
369
0
        link_target,
370
0
        newname);
371
0
  if (req == NULL) {
372
0
    status = NT_STATUS_NO_MEMORY;
373
0
    goto fail;
374
0
  }
375
376
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
377
0
    goto fail;
378
0
  }
379
380
0
  status = cli_posix_symlink_recv(req);
381
382
0
 fail:
383
0
  TALLOC_FREE(frame);
384
0
  return status;
385
0
}
386
387
/****************************************************************************
388
 Read a POSIX symlink.
389
****************************************************************************/
390
391
struct cli_posix_readlink_state {
392
  struct cli_state *cli;
393
  char *converted;
394
};
395
396
static void cli_posix_readlink_done(struct tevent_req *subreq);
397
398
struct tevent_req *cli_posix_readlink_send(TALLOC_CTX *mem_ctx,
399
          struct tevent_context *ev,
400
          struct cli_state *cli,
401
          const char *fname)
402
0
{
403
0
  struct tevent_req *req = NULL, *subreq = NULL;
404
0
  struct cli_posix_readlink_state *state = NULL;
405
406
0
  req = tevent_req_create(
407
0
    mem_ctx, &state, struct cli_posix_readlink_state);
408
0
  if (req == NULL) {
409
0
    return NULL;
410
0
  }
411
0
  state->cli = cli;
412
413
0
  subreq = cli_qpathinfo_send(
414
0
    state,
415
0
    ev,
416
0
    cli,
417
0
    fname,
418
0
    SMB_QUERY_FILE_UNIX_LINK,
419
0
    1,
420
0
    UINT16_MAX);
421
0
  if (tevent_req_nomem(subreq, req)) {
422
0
    return tevent_req_post(req, ev);
423
0
  }
424
0
  tevent_req_set_callback(subreq, cli_posix_readlink_done, req);
425
0
  return req;
426
0
}
427
428
static void cli_posix_readlink_done(struct tevent_req *subreq)
429
0
{
430
0
  struct tevent_req *req = tevent_req_callback_data(
431
0
    subreq, struct tevent_req);
432
0
  struct cli_posix_readlink_state *state = tevent_req_data(
433
0
    req, struct cli_posix_readlink_state);
434
0
  NTSTATUS status;
435
0
  uint8_t *data = NULL;
436
0
  uint32_t num_data = 0;
437
0
  charset_t charset;
438
0
  size_t converted_size;
439
0
  bool ok;
440
441
0
  status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
442
0
  TALLOC_FREE(subreq);
443
0
  if (tevent_req_nterror(req, status)) {
444
0
    return;
445
0
  }
446
  /*
447
   * num_data is > 1, we've given 1 as minimum to cli_qpathinfo_send
448
   */
449
0
  if (data == NULL || data[num_data-1] != '\0') {
450
0
    tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
451
0
    return;
452
0
  }
453
454
0
  charset = smbXcli_conn_use_unicode(state->cli->conn) ?
455
0
    CH_UTF16LE : CH_DOS;
456
457
  /* The returned data is a pushed string, not raw data. */
458
0
  ok = convert_string_talloc(
459
0
    state,
460
0
    charset,
461
0
    CH_UNIX,
462
0
    data,
463
0
    num_data,
464
0
    &state->converted,
465
0
    &converted_size);
466
0
  if (!ok) {
467
0
    tevent_req_oom(req);
468
0
    return;
469
0
  }
470
0
  tevent_req_done(req);
471
0
}
472
473
NTSTATUS cli_posix_readlink_recv(
474
  struct tevent_req *req, TALLOC_CTX *mem_ctx, char **target)
475
0
{
476
0
  struct cli_posix_readlink_state *state = tevent_req_data(
477
0
    req, struct cli_posix_readlink_state);
478
0
  NTSTATUS status;
479
480
0
  if (tevent_req_is_nterror(req, &status)) {
481
0
    return status;
482
0
  }
483
0
  *target = talloc_move(mem_ctx, &state->converted);
484
0
  tevent_req_received(req);
485
0
  return NT_STATUS_OK;
486
0
}
487
488
/****************************************************************************
489
 Hard link a file (UNIX extensions).
490
****************************************************************************/
491
492
struct cli_posix_hardlink_state {
493
  uint8_t dummy;
494
};
495
496
static void cli_posix_hardlink_done(struct tevent_req *subreq);
497
498
struct tevent_req *cli_posix_hardlink_send(TALLOC_CTX *mem_ctx,
499
          struct tevent_context *ev,
500
          struct cli_state *cli,
501
          const char *oldname,
502
          const char *newname)
503
0
{
504
0
  struct tevent_req *req = NULL, *subreq = NULL;
505
0
  struct cli_posix_hardlink_state *state = NULL;
506
507
0
  req = tevent_req_create(
508
0
    mem_ctx, &state, struct cli_posix_hardlink_state);
509
0
  if (req == NULL) {
510
0
    return NULL;
511
0
  }
512
513
0
  subreq = cli_posix_link_internal_send(
514
0
    state, ev, cli, SMB_SET_FILE_UNIX_HLINK, oldname, newname);
515
0
  if (tevent_req_nomem(subreq, req)) {
516
0
    return tevent_req_post(req, ev);
517
0
  }
518
0
  tevent_req_set_callback(subreq, cli_posix_hardlink_done, req);
519
0
  return req;
520
0
}
521
522
static void cli_posix_hardlink_done(struct tevent_req *subreq)
523
0
{
524
0
  NTSTATUS status = cli_posix_link_internal_recv(subreq);
525
0
  tevent_req_simple_finish_ntstatus(subreq, status);
526
0
}
527
528
NTSTATUS cli_posix_hardlink_recv(struct tevent_req *req)
529
0
{
530
0
  return tevent_req_simple_recv_ntstatus(req);
531
0
}
532
533
NTSTATUS cli_posix_hardlink(struct cli_state *cli,
534
      const char *oldname,
535
      const char *newname)
536
0
{
537
0
  TALLOC_CTX *frame = talloc_stackframe();
538
0
  struct tevent_context *ev = NULL;
539
0
  struct tevent_req *req = NULL;
540
0
  NTSTATUS status = NT_STATUS_OK;
541
542
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
543
    /*
544
     * Can't use sync call while an async call is in flight
545
     */
546
0
    status = NT_STATUS_INVALID_PARAMETER;
547
0
    goto fail;
548
0
  }
549
550
0
  ev = samba_tevent_context_init(frame);
551
0
  if (ev == NULL) {
552
0
    status = NT_STATUS_NO_MEMORY;
553
0
    goto fail;
554
0
  }
555
556
0
  req = cli_posix_hardlink_send(frame,
557
0
        ev,
558
0
        cli,
559
0
        oldname,
560
0
        newname);
561
0
  if (req == NULL) {
562
0
    status = NT_STATUS_NO_MEMORY;
563
0
    goto fail;
564
0
  }
565
566
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
567
0
    goto fail;
568
0
  }
569
570
0
  status = cli_posix_hardlink_recv(req);
571
572
0
 fail:
573
0
  TALLOC_FREE(frame);
574
0
  return status;
575
0
}
576
577
/****************************************************************************
578
 Do a POSIX getacl - pathname based ACL get (UNIX extensions).
579
****************************************************************************/
580
581
struct getacl_state {
582
  uint32_t num_data;
583
  uint8_t *data;
584
};
585
586
static void cli_posix_getacl_done(struct tevent_req *subreq);
587
588
struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx,
589
          struct tevent_context *ev,
590
          struct cli_state *cli,
591
          const char *fname)
592
0
{
593
0
  struct tevent_req *req = NULL, *subreq = NULL;
594
0
  struct getacl_state *state = NULL;
595
596
0
  req = tevent_req_create(mem_ctx, &state, struct getacl_state);
597
0
  if (req == NULL) {
598
0
    return NULL;
599
0
  }
600
0
  subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_QUERY_POSIX_ACL,
601
0
            0, CLI_BUFFER_SIZE);
602
0
  if (tevent_req_nomem(subreq, req)) {
603
0
    return tevent_req_post(req, ev);
604
0
  }
605
0
  tevent_req_set_callback(subreq, cli_posix_getacl_done, req);
606
0
  return req;
607
0
}
608
609
static void cli_posix_getacl_done(struct tevent_req *subreq)
610
0
{
611
0
  struct tevent_req *req = tevent_req_callback_data(
612
0
    subreq, struct tevent_req);
613
0
  struct getacl_state *state = tevent_req_data(
614
0
    req, struct getacl_state);
615
0
  NTSTATUS status;
616
617
0
  status = cli_qpathinfo_recv(subreq, state, &state->data,
618
0
            &state->num_data);
619
0
  TALLOC_FREE(subreq);
620
0
  if (tevent_req_nterror(req, status)) {
621
0
    return;
622
0
  }
623
0
  tevent_req_done(req);
624
0
}
625
626
NTSTATUS cli_posix_getacl_recv(struct tevent_req *req,
627
        TALLOC_CTX *mem_ctx,
628
        size_t *prb_size,
629
        char **retbuf)
630
0
{
631
0
  struct getacl_state *state = tevent_req_data(req, struct getacl_state);
632
0
  NTSTATUS status;
633
634
0
  if (tevent_req_is_nterror(req, &status)) {
635
0
    return status;
636
0
  }
637
0
  *prb_size = (size_t)state->num_data;
638
0
  *retbuf = (char *)talloc_move(mem_ctx, &state->data);
639
0
  return NT_STATUS_OK;
640
0
}
641
642
NTSTATUS cli_posix_getacl(struct cli_state *cli,
643
      const char *fname,
644
      TALLOC_CTX *mem_ctx,
645
      size_t *prb_size,
646
      char **retbuf)
647
0
{
648
0
  TALLOC_CTX *frame = talloc_stackframe();
649
0
  struct tevent_context *ev = NULL;
650
0
  struct tevent_req *req = NULL;
651
0
  NTSTATUS status = NT_STATUS_OK;
652
653
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
654
    /*
655
     * Can't use sync call while an async call is in flight
656
     */
657
0
    status = NT_STATUS_INVALID_PARAMETER;
658
0
    goto fail;
659
0
  }
660
661
0
  ev = samba_tevent_context_init(frame);
662
0
  if (ev == NULL) {
663
0
    status = NT_STATUS_NO_MEMORY;
664
0
    goto fail;
665
0
  }
666
667
0
  req = cli_posix_getacl_send(frame,
668
0
        ev,
669
0
        cli,
670
0
        fname);
671
0
  if (req == NULL) {
672
0
    status = NT_STATUS_NO_MEMORY;
673
0
    goto fail;
674
0
  }
675
676
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
677
0
    goto fail;
678
0
  }
679
680
0
  status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf);
681
682
0
 fail:
683
0
  TALLOC_FREE(frame);
684
0
  return status;
685
0
}
686
687
/****************************************************************************
688
 Do a POSIX setacl - pathname based ACL set (UNIX extensions).
689
****************************************************************************/
690
691
struct setacl_state {
692
  uint8_t *data;
693
};
694
695
static void cli_posix_setacl_done(struct tevent_req *subreq);
696
697
struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx,
698
          struct tevent_context *ev,
699
          struct cli_state *cli,
700
          const char *fname,
701
          const void *data,
702
          size_t num_data)
703
0
{
704
0
  struct tevent_req *req = NULL, *subreq = NULL;
705
0
  struct setacl_state *state = NULL;
706
707
0
  req = tevent_req_create(mem_ctx, &state, struct setacl_state);
708
0
  if (req == NULL) {
709
0
    return NULL;
710
0
  }
711
0
  state->data = talloc_memdup(state, data, num_data);
712
0
  if (tevent_req_nomem(state->data, req)) {
713
0
    return tevent_req_post(req, ev);
714
0
  }
715
716
0
  subreq = cli_setpathinfo_send(state,
717
0
        ev,
718
0
        cli,
719
0
        SMB_SET_POSIX_ACL,
720
0
        fname,
721
0
        state->data,
722
0
        num_data);
723
0
  if (tevent_req_nomem(subreq, req)) {
724
0
    return tevent_req_post(req, ev);
725
0
  }
726
0
  tevent_req_set_callback(subreq, cli_posix_setacl_done, req);
727
0
  return req;
728
0
}
729
730
static void cli_posix_setacl_done(struct tevent_req *subreq)
731
0
{
732
0
  NTSTATUS status = cli_setpathinfo_recv(subreq);
733
0
  tevent_req_simple_finish_ntstatus(subreq, status);
734
0
}
735
736
NTSTATUS cli_posix_setacl_recv(struct tevent_req *req)
737
0
{
738
0
  return tevent_req_simple_recv_ntstatus(req);
739
0
}
740
741
NTSTATUS cli_posix_setacl(struct cli_state *cli,
742
      const char *fname,
743
      const void *acl_buf,
744
      size_t acl_buf_size)
745
0
{
746
0
  TALLOC_CTX *frame = talloc_stackframe();
747
0
  struct tevent_context *ev = NULL;
748
0
  struct tevent_req *req = NULL;
749
0
  NTSTATUS status = NT_STATUS_OK;
750
751
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
752
    /*
753
     * Can't use sync call while an async call is in flight
754
     */
755
0
    status = NT_STATUS_INVALID_PARAMETER;
756
0
    goto fail;
757
0
  }
758
759
0
  ev = samba_tevent_context_init(frame);
760
0
  if (ev == NULL) {
761
0
    status = NT_STATUS_NO_MEMORY;
762
0
    goto fail;
763
0
  }
764
765
0
  req = cli_posix_setacl_send(frame,
766
0
        ev,
767
0
        cli,
768
0
        fname,
769
0
        acl_buf,
770
0
        acl_buf_size);
771
0
  if (req == NULL) {
772
0
    status = NT_STATUS_NO_MEMORY;
773
0
    goto fail;
774
0
  }
775
776
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
777
0
    goto fail;
778
0
  }
779
780
0
  status = cli_posix_setacl_recv(req);
781
782
0
 fail:
783
0
  TALLOC_FREE(frame);
784
0
  return status;
785
0
}
786
787
/****************************************************************************
788
 Stat a file (UNIX extensions).
789
****************************************************************************/
790
791
struct cli_posix_stat_state {
792
  struct stat_ex sbuf;
793
};
794
795
static void cli_posix_stat_done(struct tevent_req *subreq);
796
797
struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx,
798
               struct tevent_context *ev,
799
               struct cli_state *cli,
800
               const char *fname)
801
0
{
802
0
  struct tevent_req *req = NULL, *subreq = NULL;
803
0
  struct stat_state *state = NULL;
804
805
0
  req = tevent_req_create(mem_ctx, &state, struct cli_posix_stat_state);
806
0
  if (req == NULL) {
807
0
    return NULL;
808
0
  }
809
810
0
  subreq = cli_qpathinfo_send(state, ev, cli, fname,
811
0
            SMB_QUERY_FILE_UNIX_BASIC, 100, 100);
812
0
  if (tevent_req_nomem(subreq, req)) {
813
0
    return tevent_req_post(req, ev);
814
0
  }
815
0
  tevent_req_set_callback(subreq, cli_posix_stat_done, req);
816
0
  return req;
817
0
}
818
819
static void cli_posix_stat_done(struct tevent_req *subreq)
820
0
{
821
0
  struct tevent_req *req = tevent_req_callback_data(
822
0
        subreq, struct tevent_req);
823
0
  struct cli_posix_stat_state *state = tevent_req_data(
824
0
    req, struct cli_posix_stat_state);
825
0
  SMB_STRUCT_STAT *sbuf = &state->sbuf;
826
0
  uint8_t *data;
827
0
  uint32_t num_data = 0;
828
0
  NTSTATUS status;
829
830
0
  status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
831
0
  TALLOC_FREE(subreq);
832
0
  if (tevent_req_nterror(req, status)) {
833
0
    return;
834
0
  }
835
836
0
  if (num_data != 100) {
837
    /*
838
     * Paranoia, cli_qpathinfo should have guaranteed
839
     * this, but you never know...
840
     */
841
0
    tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
842
0
    return;
843
0
  }
844
845
  /* total size, in bytes */
846
0
  sbuf->st_ex_size = BVAL(data, 0);
847
848
  /* number of blocks allocated */
849
0
  sbuf->st_ex_blocks = BVAL(data,8);
850
0
#if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
851
0
  sbuf->st_ex_blocks /= STAT_ST_BLOCKSIZE;
852
#else
853
  /* assume 512 byte blocks */
854
  sbuf->st_ex_blocks /= 512;
855
#endif
856
  /* time of last change */
857
0
  sbuf->st_ex_ctime = interpret_long_date(BVAL(data, 16));
858
859
  /* time of last access */
860
0
  sbuf->st_ex_atime = interpret_long_date(BVAL(data, 24));
861
862
  /* time of last modification */
863
0
  sbuf->st_ex_mtime = interpret_long_date(BVAL(data, 32));
864
865
0
  sbuf->st_ex_uid = (uid_t) IVAL(data, 40); /* user ID of owner */
866
0
  sbuf->st_ex_gid = (gid_t) IVAL(data, 48); /* group ID of owner */
867
0
  sbuf->st_ex_mode = wire_filetype_to_unix(IVAL(data, 56));
868
869
0
#if defined(HAVE_MAKEDEV)
870
0
  {
871
0
    uint32_t dev_major = IVAL(data,60);
872
0
    uint32_t dev_minor = IVAL(data,68);
873
0
    sbuf->st_ex_rdev = makedev(dev_major, dev_minor);
874
0
  }
875
0
#endif
876
  /* inode */
877
0
  sbuf->st_ex_ino = (SMB_INO_T)BVAL(data, 76);
878
879
  /* protection */
880
0
  sbuf->st_ex_mode |= wire_perms_to_unix(IVAL(data, 84));
881
882
  /* number of hard links */
883
0
  sbuf->st_ex_nlink = BIG_UINT(data, 92);
884
885
0
  tevent_req_done(req);
886
0
}
887
888
NTSTATUS cli_posix_stat_recv(struct tevent_req *req, struct stat_ex *sbuf)
889
0
{
890
0
  struct cli_posix_stat_state *state = tevent_req_data(
891
0
    req, struct cli_posix_stat_state);
892
0
  NTSTATUS status;
893
894
0
  if (tevent_req_is_nterror(req, &status)) {
895
0
    return status;
896
0
  }
897
0
  *sbuf = state->sbuf;
898
0
  return NT_STATUS_OK;
899
0
}
900
901
NTSTATUS cli_posix_stat(struct cli_state *cli,
902
      const char *fname,
903
      struct stat_ex *sbuf)
904
0
{
905
0
  TALLOC_CTX *frame = talloc_stackframe();
906
0
  struct tevent_context *ev = NULL;
907
0
  struct tevent_req *req = NULL;
908
0
  NTSTATUS status = NT_STATUS_OK;
909
910
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
911
    /*
912
     * Can't use sync call while an async call is in flight
913
     */
914
0
    status = NT_STATUS_INVALID_PARAMETER;
915
0
    goto fail;
916
0
  }
917
918
0
  ev = samba_tevent_context_init(frame);
919
0
  if (ev == NULL) {
920
0
    status = NT_STATUS_NO_MEMORY;
921
0
    goto fail;
922
0
  }
923
924
0
  req = cli_posix_stat_send(frame, ev, cli, fname);
925
0
  if (req == NULL) {
926
0
    status = NT_STATUS_NO_MEMORY;
927
0
    goto fail;
928
0
  }
929
930
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
931
0
    goto fail;
932
0
  }
933
934
0
  status = cli_posix_stat_recv(req, sbuf);
935
936
0
 fail:
937
0
  TALLOC_FREE(frame);
938
0
  return status;
939
0
}
940
941
/****************************************************************************
942
 Chmod or chown a file internal (UNIX extensions).
943
****************************************************************************/
944
945
struct cli_posix_chown_chmod_internal_state {
946
  uint8_t data[100];
947
};
948
949
static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq);
950
951
static struct tevent_req *cli_posix_chown_chmod_internal_send(TALLOC_CTX *mem_ctx,
952
          struct tevent_context *ev,
953
          struct cli_state *cli,
954
          const char *fname,
955
          uint32_t mode,
956
          uint32_t uid,
957
          uint32_t gid)
958
0
{
959
0
  struct tevent_req *req = NULL, *subreq = NULL;
960
0
  struct cli_posix_chown_chmod_internal_state *state = NULL;
961
962
0
  req = tevent_req_create(mem_ctx, &state,
963
0
        struct cli_posix_chown_chmod_internal_state);
964
0
  if (req == NULL) {
965
0
    return NULL;
966
0
  }
967
968
0
  memset(state->data, 0xff, 40); /* Set all sizes/times to no change. */
969
0
  SIVAL(state->data,40,uid);
970
0
  SIVAL(state->data,48,gid);
971
0
  SIVAL(state->data,84,mode);
972
973
0
  subreq = cli_setpathinfo_send(state, ev, cli, SMB_SET_FILE_UNIX_BASIC,
974
0
              fname, state->data, sizeof(state->data));
975
0
  if (tevent_req_nomem(subreq, req)) {
976
0
    return tevent_req_post(req, ev);
977
0
  }
978
0
  tevent_req_set_callback(subreq, cli_posix_chown_chmod_internal_done,
979
0
        req);
980
0
  return req;
981
0
}
982
983
static void cli_posix_chown_chmod_internal_done(struct tevent_req *subreq)
984
0
{
985
0
  NTSTATUS status = cli_setpathinfo_recv(subreq);
986
0
  tevent_req_simple_finish_ntstatus(subreq, status);
987
0
}
988
989
static NTSTATUS cli_posix_chown_chmod_internal_recv(struct tevent_req *req)
990
0
{
991
0
  return tevent_req_simple_recv_ntstatus(req);
992
0
}
993
994
struct cli_fchmod_state {
995
  uint8_t data[100]; /* smb1 posix extensions */
996
};
997
998
static void cli_fchmod_done1(struct tevent_req *subreq);
999
static void cli_fchmod_done2(struct tevent_req *subreq);
1000
1001
struct tevent_req *cli_fchmod_send(TALLOC_CTX *mem_ctx,
1002
           struct tevent_context *ev,
1003
           struct cli_state *cli,
1004
           uint16_t fnum,
1005
           mode_t mode)
1006
0
{
1007
0
  struct tevent_req *req = NULL, *subreq = NULL;
1008
0
  struct cli_fchmod_state *state = NULL;
1009
0
  const enum protocol_types proto = smbXcli_conn_protocol(cli->conn);
1010
1011
0
  req = tevent_req_create(mem_ctx, &state, struct cli_fchmod_state);
1012
0
  if (req == NULL) {
1013
0
    return NULL;
1014
0
  }
1015
1016
0
  if ((proto < PROTOCOL_SMB2_02) && SERVER_HAS_UNIX_CIFS(cli)) {
1017
0
    memset(state->data,
1018
0
           0xff,
1019
0
           40); /* Set all sizes/times to no change. */
1020
0
    PUSH_LE_U32(state->data, 40, SMB_UID_NO_CHANGE);
1021
0
    PUSH_LE_U32(state->data, 48, SMB_GID_NO_CHANGE);
1022
0
    PUSH_LE_U32(state->data, 84, mode);
1023
1024
0
    subreq = cli_setfileinfo_send(state,
1025
0
                ev,
1026
0
                cli,
1027
0
                fnum,
1028
0
                SMB_SET_FILE_UNIX_BASIC,
1029
0
                state->data,
1030
0
                sizeof(state->data));
1031
0
    if (tevent_req_nomem(subreq, req)) {
1032
0
      return tevent_req_post(req, ev);
1033
0
    }
1034
0
    tevent_req_set_callback(subreq, cli_fchmod_done1, req);
1035
0
    return req;
1036
0
  }
1037
1038
0
  if ((proto >= PROTOCOL_SMB3_11) && cli_smb2_fnum_is_posix(cli, fnum)) {
1039
0
    struct security_ace ace = {
1040
0
      .type = SEC_ACE_TYPE_ACCESS_ALLOWED,
1041
0
      .trustee = global_sid_Unix_NFS_Mode,
1042
0
    };
1043
0
    struct security_acl acl = {
1044
0
      .revision = SECURITY_ACL_REVISION_NT4,
1045
0
      .num_aces = 1,
1046
0
      .aces = &ace,
1047
0
    };
1048
0
    struct security_descriptor *sd = NULL;
1049
1050
0
    sid_append_rid(&ace.trustee, mode);
1051
1052
0
    sd = make_sec_desc(state,
1053
0
           SECURITY_DESCRIPTOR_REVISION_1,
1054
0
           SEC_DESC_SELF_RELATIVE |
1055
0
             SEC_DESC_DACL_PRESENT,
1056
0
           NULL,
1057
0
           NULL,
1058
0
           NULL,
1059
0
           &acl,
1060
0
           NULL);
1061
0
    if (tevent_req_nomem(sd, req)) {
1062
0
      return tevent_req_post(req, ev);
1063
0
    }
1064
1065
0
    subreq = cli_set_security_descriptor_send(
1066
0
      state, ev, cli, fnum, SECINFO_DACL, sd);
1067
0
    if (tevent_req_nomem(subreq, req)) {
1068
0
      return tevent_req_post(req, ev);
1069
0
    }
1070
0
    tevent_req_set_callback(subreq, cli_fchmod_done2, req);
1071
0
    return req;
1072
0
  }
1073
1074
0
  tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
1075
0
  return tevent_req_post(req, ev);
1076
0
}
1077
1078
static void cli_fchmod_done1(struct tevent_req *subreq)
1079
0
{
1080
0
  NTSTATUS status = cli_setfileinfo_recv(subreq);
1081
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1082
0
}
1083
1084
static void cli_fchmod_done2(struct tevent_req *subreq)
1085
0
{
1086
0
  NTSTATUS status = cli_set_security_descriptor_recv(subreq);
1087
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1088
0
}
1089
1090
NTSTATUS cli_fchmod_recv(struct tevent_req *req)
1091
0
{
1092
0
  return tevent_req_simple_recv_ntstatus(req);
1093
0
}
1094
1095
struct cli_chmod_state {
1096
  struct tevent_context *ev;
1097
  struct cli_state *cli;
1098
  mode_t mode;
1099
1100
  uint16_t fnum;
1101
1102
  NTSTATUS fchmod_status;
1103
1104
  uint8_t data[100]; /* smb1 posix extensions */
1105
};
1106
1107
static void cli_chmod_opened(struct tevent_req *subreq);
1108
static void cli_chmod_done(struct tevent_req *subreq);
1109
static void cli_chmod_closed(struct tevent_req *subreq);
1110
1111
struct tevent_req *cli_chmod_send(TALLOC_CTX *mem_ctx,
1112
          struct tevent_context *ev,
1113
          struct cli_state *cli,
1114
          const char *fname,
1115
          mode_t mode)
1116
0
{
1117
0
  struct tevent_req *req = NULL, *subreq = NULL;
1118
0
  struct cli_chmod_state *state = NULL;
1119
1120
0
  req = tevent_req_create(mem_ctx, &state, struct cli_chmod_state);
1121
0
  if (req == NULL) {
1122
0
    return NULL;
1123
0
  }
1124
0
  state->ev = ev;
1125
0
  state->cli = cli;
1126
0
  state->mode = mode;
1127
1128
0
  subreq = cli_ntcreate_send(
1129
0
    state,            /* mem_ctx */
1130
0
    ev,           /* ev */
1131
0
    cli,            /* cli */
1132
0
    fname,            /* fname */
1133
0
    0,            /* create_flags */
1134
0
    SEC_STD_WRITE_DAC,       /* desired_access */
1135
0
    0,            /* file_attributes */
1136
0
    FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1137
0
    FILE_OPEN,         /* create_disposition */
1138
0
    0x0,            /* create_options */
1139
0
    SMB2_IMPERSONATION_IMPERSONATION,   /* impersonation_level */
1140
0
    0x0);           /* SecurityFlags */
1141
0
  if (tevent_req_nomem(subreq, req)) {
1142
0
    return tevent_req_post(req, ev);
1143
0
  }
1144
0
  tevent_req_set_callback(subreq, cli_chmod_opened, req);
1145
0
  return req;
1146
0
}
1147
1148
static void cli_chmod_opened(struct tevent_req *subreq)
1149
0
{
1150
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
1151
0
                struct tevent_req);
1152
0
  struct cli_chmod_state *state = tevent_req_data(
1153
0
    req, struct cli_chmod_state);
1154
0
  NTSTATUS status;
1155
1156
0
  status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
1157
0
  TALLOC_FREE(subreq);
1158
0
  if (tevent_req_nterror(req, status)) {
1159
0
    return;
1160
0
  }
1161
1162
0
  subreq = cli_fchmod_send(
1163
0
    state, state->ev, state->cli, state->fnum, state->mode);
1164
0
  if (tevent_req_nomem(subreq, req)) {
1165
0
    return;
1166
0
  }
1167
0
  tevent_req_set_callback(subreq, cli_chmod_done, req);
1168
0
}
1169
1170
static void cli_chmod_done(struct tevent_req *subreq)
1171
0
{
1172
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
1173
0
                struct tevent_req);
1174
0
  struct cli_chmod_state *state = tevent_req_data(
1175
0
    req, struct cli_chmod_state);
1176
1177
0
  state->fchmod_status = cli_fchmod_recv(subreq);
1178
0
  TALLOC_FREE(subreq);
1179
1180
0
  subreq = cli_close_send(state, state->ev, state->cli, state->fnum, 0);
1181
0
  if (tevent_req_nomem(subreq, req)) {
1182
0
    return;
1183
0
  }
1184
0
  tevent_req_set_callback(subreq, cli_chmod_closed, req);
1185
0
}
1186
1187
static void cli_chmod_closed(struct tevent_req *subreq)
1188
0
{
1189
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
1190
0
                struct tevent_req);
1191
0
  NTSTATUS status;
1192
1193
0
  status = cli_close_recv(subreq);
1194
0
  TALLOC_FREE(subreq);
1195
0
  if (tevent_req_nterror(req, status)) {
1196
0
    return;
1197
0
  }
1198
0
  tevent_req_done(req);
1199
0
}
1200
1201
NTSTATUS cli_chmod_recv(struct tevent_req *req)
1202
0
{
1203
0
  struct cli_chmod_state *state = tevent_req_data(
1204
0
    req, struct cli_chmod_state);
1205
0
  NTSTATUS status;
1206
1207
0
  if (tevent_req_is_nterror(req, &status)) {
1208
0
    tevent_req_received(req);
1209
0
    return status;
1210
0
  }
1211
0
  tevent_req_received(req);
1212
0
  return state->fchmod_status;
1213
0
}
1214
1215
NTSTATUS cli_chmod(struct cli_state *cli, const char *fname, mode_t mode)
1216
0
{
1217
0
  TALLOC_CTX *frame = talloc_stackframe();
1218
0
  struct tevent_context *ev = NULL;
1219
0
  struct tevent_req *req = NULL;
1220
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
1221
1222
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
1223
    /*
1224
     * Can't use sync call while an async call is in flight
1225
     */
1226
0
    status = NT_STATUS_INVALID_PARAMETER;
1227
0
    goto fail;
1228
0
  }
1229
0
  ev = samba_tevent_context_init(frame);
1230
0
  if (ev == NULL) {
1231
0
    goto fail;
1232
0
  }
1233
0
  req = cli_chmod_send(frame, ev, cli, fname, mode);
1234
0
  if (req == NULL) {
1235
0
    goto fail;
1236
0
  }
1237
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1238
0
    goto fail;
1239
0
  }
1240
0
  status = cli_chmod_recv(req);
1241
0
fail:
1242
0
  TALLOC_FREE(frame);
1243
0
  return status;
1244
0
}
1245
1246
/****************************************************************************
1247
 chown a file (UNIX extensions).
1248
****************************************************************************/
1249
1250
struct cli_posix_chown_state {
1251
  uint8_t dummy;
1252
};
1253
1254
static void cli_posix_chown_done(struct tevent_req *subreq);
1255
1256
struct tevent_req *cli_posix_chown_send(TALLOC_CTX *mem_ctx,
1257
          struct tevent_context *ev,
1258
          struct cli_state *cli,
1259
          const char *fname,
1260
          uid_t uid,
1261
          gid_t gid)
1262
0
{
1263
0
  struct tevent_req *req = NULL, *subreq = NULL;
1264
0
  struct cli_posix_chown_state *state = NULL;
1265
1266
0
  req = tevent_req_create(
1267
0
    mem_ctx, &state, struct cli_posix_chown_state);
1268
0
  if (req == NULL) {
1269
0
    return NULL;
1270
0
  }
1271
1272
0
  subreq = cli_posix_chown_chmod_internal_send(
1273
0
    state,
1274
0
    ev,
1275
0
    cli,
1276
0
    fname,
1277
0
    SMB_MODE_NO_CHANGE,
1278
0
    (uint32_t)uid,
1279
0
    (uint32_t)gid);
1280
0
  if (tevent_req_nomem(subreq, req)) {
1281
0
    return tevent_req_post(req, ev);
1282
0
  }
1283
0
  tevent_req_set_callback(subreq, cli_posix_chown_done, req);
1284
0
  return req;
1285
0
}
1286
1287
static void cli_posix_chown_done(struct tevent_req *subreq)
1288
0
{
1289
0
  NTSTATUS status = cli_posix_chown_chmod_internal_recv(subreq);
1290
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1291
0
}
1292
1293
NTSTATUS cli_posix_chown_recv(struct tevent_req *req)
1294
0
{
1295
0
  return tevent_req_simple_recv_ntstatus(req);
1296
0
}
1297
1298
NTSTATUS cli_posix_chown(struct cli_state *cli,
1299
      const char *fname,
1300
      uid_t uid,
1301
      gid_t gid)
1302
0
{
1303
0
  TALLOC_CTX *frame = talloc_stackframe();
1304
0
  struct tevent_context *ev = NULL;
1305
0
  struct tevent_req *req = NULL;
1306
0
  NTSTATUS status = NT_STATUS_OK;
1307
1308
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
1309
    /*
1310
     * Can't use sync call while an async call is in flight
1311
     */
1312
0
    status = NT_STATUS_INVALID_PARAMETER;
1313
0
    goto fail;
1314
0
  }
1315
1316
0
  ev = samba_tevent_context_init(frame);
1317
0
  if (ev == NULL) {
1318
0
    status = NT_STATUS_NO_MEMORY;
1319
0
    goto fail;
1320
0
  }
1321
1322
0
  req = cli_posix_chown_send(frame,
1323
0
        ev,
1324
0
        cli,
1325
0
        fname,
1326
0
        uid,
1327
0
        gid);
1328
0
  if (req == NULL) {
1329
0
    status = NT_STATUS_NO_MEMORY;
1330
0
    goto fail;
1331
0
  }
1332
1333
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1334
0
    goto fail;
1335
0
  }
1336
1337
0
  status = cli_posix_chown_recv(req);
1338
1339
0
 fail:
1340
0
  TALLOC_FREE(frame);
1341
0
  return status;
1342
0
}
1343
1344
struct cli_smb1_posix_mknod_state {
1345
  uint8_t data[100];
1346
};
1347
1348
static void cli_smb1_posix_mknod_done(struct tevent_req *subreq);
1349
1350
static struct tevent_req *cli_smb1_posix_mknod_send(
1351
  TALLOC_CTX *mem_ctx,
1352
  struct tevent_context *ev,
1353
  struct cli_state *cli,
1354
  const char *fname,
1355
  mode_t mode,
1356
  dev_t dev)
1357
0
{
1358
0
  struct tevent_req *req = NULL, *subreq = NULL;
1359
0
  struct cli_smb1_posix_mknod_state *state = NULL;
1360
0
  mode_t type = mode & S_IFMT;
1361
0
  uint32_t smb_unix_type = 0xFFFFFFFF;
1362
1363
0
  req = tevent_req_create(
1364
0
    mem_ctx, &state, struct cli_smb1_posix_mknod_state);
1365
0
  if (req == NULL) {
1366
0
    return NULL;
1367
0
  }
1368
  /*
1369
   * Set all sizes/times/ids to no change.
1370
   */
1371
0
  memset(state->data, 0xff, 56);
1372
1373
0
  switch (type) {
1374
0
  case S_IFREG:
1375
0
    smb_unix_type = UNIX_TYPE_FILE;
1376
0
    break;
1377
0
  case S_IFDIR:
1378
0
    smb_unix_type = UNIX_TYPE_DIR;
1379
0
    break;
1380
0
  case S_IFLNK:
1381
0
    smb_unix_type = UNIX_TYPE_SYMLINK;
1382
0
    break;
1383
0
  case S_IFCHR:
1384
0
    smb_unix_type = UNIX_TYPE_CHARDEV;
1385
0
    break;
1386
0
  case S_IFBLK:
1387
0
    smb_unix_type = UNIX_TYPE_BLKDEV;
1388
0
    break;
1389
0
  case S_IFIFO:
1390
0
    smb_unix_type = UNIX_TYPE_FIFO;
1391
0
    break;
1392
0
  case S_IFSOCK:
1393
0
    smb_unix_type = UNIX_TYPE_SOCKET;
1394
0
    break;
1395
0
  }
1396
0
  PUSH_LE_U32(state->data, 56, smb_unix_type);
1397
1398
0
  if ((type == S_IFCHR) || (type == S_IFBLK)) {
1399
0
    PUSH_LE_U64(state->data, 60, unix_dev_major(dev));
1400
0
    PUSH_LE_U64(state->data, 68, unix_dev_minor(dev));
1401
0
  }
1402
1403
0
  PUSH_LE_U32(state->data, 84, unix_perms_to_wire(mode));
1404
1405
0
  subreq = cli_setpathinfo_send(
1406
0
    state,
1407
0
    ev,
1408
0
    cli,
1409
0
    SMB_SET_FILE_UNIX_BASIC,
1410
0
    fname,
1411
0
    state->data,
1412
0
    sizeof(state->data));
1413
0
  if (tevent_req_nomem(subreq, req)) {
1414
0
    return tevent_req_post(req, ev);
1415
0
  }
1416
0
  tevent_req_set_callback(subreq, cli_smb1_posix_mknod_done, req);
1417
0
  return req;
1418
0
}
1419
1420
static void cli_smb1_posix_mknod_done(struct tevent_req *subreq)
1421
0
{
1422
0
  NTSTATUS status = cli_setpathinfo_recv(subreq);
1423
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1424
0
}
1425
1426
static NTSTATUS cli_smb1_posix_mknod_recv(struct tevent_req *req)
1427
0
{
1428
0
  return tevent_req_simple_recv_ntstatus(req);
1429
0
}
1430
1431
struct cli_mknod_state {
1432
  uint8_t buf[24];
1433
};
1434
1435
static void cli_mknod_done1(struct tevent_req *subreq);
1436
static void cli_mknod_reparse_done(struct tevent_req *subreq);
1437
1438
struct tevent_req *cli_mknod_send(
1439
  TALLOC_CTX *mem_ctx,
1440
  struct tevent_context *ev,
1441
  struct cli_state *cli,
1442
  const char *fname,
1443
  mode_t mode,
1444
  dev_t dev)
1445
0
{
1446
0
  struct tevent_req *req = NULL, *subreq = NULL;
1447
0
  struct cli_mknod_state *state = NULL;
1448
0
  struct reparse_data_buffer reparse_buf = {
1449
0
    .tag = IO_REPARSE_TAG_NFS,
1450
0
  };
1451
0
  struct nfs_reparse_data_buffer *nfs = &reparse_buf.parsed.nfs;
1452
0
  ssize_t buflen;
1453
1454
0
  req = tevent_req_create(mem_ctx, &state, struct cli_mknod_state);
1455
0
  if (req == NULL) {
1456
0
    return NULL;
1457
0
  }
1458
1459
0
  if (cli->requested_posix_capabilities != 0) {
1460
0
    subreq = cli_smb1_posix_mknod_send(
1461
0
      state, ev, cli, fname, mode, dev);
1462
0
    if (tevent_req_nomem(subreq, req)) {
1463
0
      return tevent_req_post(req, ev);
1464
0
    }
1465
0
    tevent_req_set_callback(subreq, cli_mknod_done1, req);
1466
0
    return req;
1467
0
  }
1468
1469
  /*
1470
   * Ignored for all but BLK and CHR
1471
   */
1472
0
  nfs->data.dev.major = major(dev);
1473
0
  nfs->data.dev.minor = minor(dev);
1474
1475
0
  switch (mode & S_IFMT) {
1476
0
  case S_IFIFO:
1477
0
    nfs->type = NFS_SPECFILE_FIFO;
1478
0
    break;
1479
0
  case S_IFSOCK:
1480
0
    nfs->type = NFS_SPECFILE_SOCK;
1481
0
    break;
1482
0
  case S_IFCHR:
1483
0
    nfs->type = NFS_SPECFILE_CHR;
1484
0
    break;
1485
0
  case S_IFBLK:
1486
0
    nfs->type = NFS_SPECFILE_BLK;
1487
0
    break;
1488
0
  }
1489
1490
0
  buflen = reparse_data_buffer_marshall(&reparse_buf,
1491
0
                state->buf,
1492
0
                sizeof(state->buf));
1493
0
  if ((buflen == -1) || (buflen > sizeof(state->buf))) {
1494
0
    tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1495
0
    return tevent_req_post(req, ev);
1496
0
  }
1497
1498
0
  subreq = cli_create_reparse_point_send(state,
1499
0
                 ev,
1500
0
                 cli,
1501
0
                 fname,
1502
0
                 (DATA_BLOB){
1503
0
                   .data = state->buf,
1504
0
                   .length = buflen,
1505
0
                 });
1506
0
  if (tevent_req_nomem(subreq, req)) {
1507
0
    return tevent_req_post(req, ev);
1508
0
  }
1509
0
  tevent_req_set_callback(subreq, cli_mknod_reparse_done, req);
1510
0
  return req;
1511
0
}
1512
1513
static void cli_mknod_done1(struct tevent_req *subreq)
1514
0
{
1515
0
  NTSTATUS status = cli_smb1_posix_mknod_recv(subreq);
1516
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1517
0
}
1518
1519
static void cli_mknod_reparse_done(struct tevent_req *subreq)
1520
0
{
1521
0
  NTSTATUS status = cli_create_reparse_point_recv(subreq);
1522
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1523
0
}
1524
1525
NTSTATUS cli_mknod_recv(struct tevent_req *req)
1526
0
{
1527
0
  return tevent_req_simple_recv_ntstatus(req);
1528
0
}
1529
1530
NTSTATUS
1531
cli_mknod(struct cli_state *cli, const char *fname, mode_t mode, dev_t dev)
1532
0
{
1533
0
  TALLOC_CTX *frame = talloc_stackframe();
1534
0
  struct tevent_context *ev;
1535
0
  struct tevent_req *req;
1536
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
1537
1538
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
1539
    /*
1540
     * Can't use sync call while an async call is in flight
1541
     */
1542
0
    status = NT_STATUS_INVALID_PARAMETER;
1543
0
    goto fail;
1544
0
  }
1545
0
  ev = samba_tevent_context_init(frame);
1546
0
  if (ev == NULL) {
1547
0
    goto fail;
1548
0
  }
1549
0
  req = cli_mknod_send(ev, ev, cli, fname, mode, dev);
1550
0
  if (req == NULL) {
1551
0
    goto fail;
1552
0
  }
1553
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1554
0
    goto fail;
1555
0
  }
1556
0
  status = cli_mknod_recv(req);
1557
0
fail:
1558
0
  TALLOC_FREE(frame);
1559
0
  return status;
1560
0
}
1561
1562
/****************************************************************************
1563
 Rename a file.
1564
****************************************************************************/
1565
1566
struct cli_smb1_rename_state {
1567
  uint8_t *data;
1568
};
1569
1570
static void cli_smb1_rename_done(struct tevent_req *subreq);
1571
1572
static struct tevent_req *cli_smb1_rename_send(TALLOC_CTX *mem_ctx,
1573
                 struct tevent_context *ev,
1574
                 struct cli_state *cli,
1575
                 const char *fname_src,
1576
                 const char *fname_dst,
1577
                 bool replace)
1578
0
{
1579
0
  NTSTATUS status;
1580
0
  struct tevent_req *req = NULL, *subreq = NULL;
1581
0
  struct cli_smb1_rename_state *state = NULL;
1582
0
  smb_ucs2_t *converted_str = NULL;
1583
0
  size_t converted_size_bytes = 0;
1584
1585
0
  req = tevent_req_create(mem_ctx, &state, struct cli_smb1_rename_state);
1586
0
  if (req == NULL) {
1587
0
    return NULL;
1588
0
  }
1589
1590
  /*
1591
   * Strip a MSDFS path from fname_dst if we were given one.
1592
   */
1593
0
  status = cli_dfs_target_check(state,
1594
0
        cli,
1595
0
        fname_dst,
1596
0
        &fname_dst);
1597
0
  if (!NT_STATUS_IS_OK(status)) {
1598
0
    goto fail;
1599
0
  }
1600
1601
0
  if (!push_ucs2_talloc(talloc_tos(), &converted_str, fname_dst,
1602
0
            &converted_size_bytes)) {
1603
0
    status = NT_STATUS_INVALID_PARAMETER;
1604
0
    goto fail;
1605
0
  }
1606
1607
  /* W2K8 insists the dest name is not null
1608
     terminated. Remove the last 2 zero bytes
1609
     and reduce the name length. */
1610
1611
0
  if (converted_size_bytes < 2) {
1612
0
    status = NT_STATUS_INVALID_PARAMETER;
1613
0
    goto fail;
1614
0
  }
1615
0
  converted_size_bytes -= 2;
1616
1617
0
  state->data =
1618
0
      talloc_zero_array(state, uint8_t, 12 + converted_size_bytes);
1619
0
  if (state->data == NULL) {
1620
0
    status = NT_STATUS_NO_MEMORY;
1621
0
    goto fail;
1622
0
  }
1623
1624
0
  if (replace) {
1625
0
    SCVAL(state->data, 0, 1);
1626
0
  }
1627
1628
0
  SIVAL(state->data, 8, converted_size_bytes);
1629
0
  memcpy(state->data + 12, converted_str, converted_size_bytes);
1630
1631
0
  TALLOC_FREE(converted_str);
1632
1633
0
  subreq = cli_setpathinfo_send(
1634
0
      state, ev, cli, SMB_FILE_RENAME_INFORMATION, fname_src, state->data,
1635
0
      talloc_get_size(state->data));
1636
0
  if (tevent_req_nomem(subreq, req)) {
1637
0
    status = NT_STATUS_NO_MEMORY;
1638
0
    goto fail;
1639
0
  }
1640
0
  tevent_req_set_callback(subreq, cli_smb1_rename_done, req);
1641
0
  return req;
1642
1643
0
fail:
1644
0
  TALLOC_FREE(converted_str);
1645
0
  tevent_req_nterror(req, status);
1646
0
  return tevent_req_post(req, ev);
1647
0
}
1648
1649
static void cli_smb1_rename_done(struct tevent_req *subreq)
1650
0
{
1651
0
  NTSTATUS status = cli_setpathinfo_recv(subreq);
1652
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1653
0
}
1654
1655
static NTSTATUS cli_smb1_rename_recv(struct tevent_req *req)
1656
0
{
1657
0
  return tevent_req_simple_recv_ntstatus(req);
1658
0
}
1659
1660
static void cli_cifs_rename_done(struct tevent_req *subreq);
1661
1662
struct cli_cifs_rename_state {
1663
  uint16_t vwv[1];
1664
};
1665
1666
static struct tevent_req *cli_cifs_rename_send(TALLOC_CTX *mem_ctx,
1667
                 struct tevent_context *ev,
1668
                 struct cli_state *cli,
1669
                 const char *fname_src,
1670
                 const char *fname_dst,
1671
                 bool replace)
1672
0
{
1673
0
  struct tevent_req *req = NULL, *subreq = NULL;
1674
0
  struct cli_cifs_rename_state *state = NULL;
1675
0
  uint8_t additional_flags = 0;
1676
0
  uint16_t additional_flags2 = 0;
1677
0
  uint8_t *bytes = NULL;
1678
0
  char *fname_src_cp = NULL;
1679
0
  char *fname_dst_cp = NULL;
1680
1681
0
  req = tevent_req_create(mem_ctx, &state, struct cli_cifs_rename_state);
1682
0
  if (req == NULL) {
1683
0
    return NULL;
1684
0
  }
1685
1686
0
  if (replace) {
1687
    /*
1688
     * CIFS doesn't support replace
1689
     */
1690
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1691
0
    return tevent_req_post(req, ev);
1692
0
  }
1693
1694
0
  SSVAL(state->vwv+0, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1695
1696
0
  bytes = talloc_array(state, uint8_t, 1);
1697
0
  if (tevent_req_nomem(bytes, req)) {
1698
0
    return tevent_req_post(req, ev);
1699
0
  }
1700
1701
  /*
1702
   * SMBmv on a DFS share uses DFS names for src and dst.
1703
   * See smbtorture3: SMB1-DFS-PATHS: test_smb1_mv().
1704
   */
1705
1706
0
  fname_src_cp = smb1_dfs_share_path(state, cli, fname_src);
1707
0
  if (tevent_req_nomem(fname_src_cp, req)) {
1708
0
    return tevent_req_post(req, ev);
1709
0
  }
1710
0
  bytes[0] = 4;
1711
0
  bytes = smb_bytes_push_str(bytes,
1712
0
           smbXcli_conn_use_unicode(cli->conn),
1713
0
           fname_src_cp,
1714
0
           strlen(fname_src_cp)+1,
1715
0
           NULL);
1716
0
  if (tevent_req_nomem(bytes, req)) {
1717
0
    return tevent_req_post(req, ev);
1718
0
  }
1719
1720
0
  if (clistr_is_previous_version_path(fname_src)) {
1721
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
1722
0
  }
1723
1724
0
  bytes = talloc_realloc(state, bytes, uint8_t,
1725
0
      talloc_get_size(bytes)+1);
1726
0
  if (tevent_req_nomem(bytes, req)) {
1727
0
    return tevent_req_post(req, ev);
1728
0
  }
1729
1730
  /*
1731
   * SMBmv on a DFS share uses DFS names for src and dst.
1732
   * See smbtorture3: SMB1-DFS-PATHS: test_smb1_mv().
1733
   */
1734
1735
0
  fname_dst_cp = smb1_dfs_share_path(state, cli, fname_dst);
1736
0
  if (tevent_req_nomem(fname_dst_cp, req)) {
1737
0
    return tevent_req_post(req, ev);
1738
0
  }
1739
0
  bytes[talloc_get_size(bytes)-1] = 4;
1740
0
  bytes = smb_bytes_push_str(bytes,
1741
0
           smbXcli_conn_use_unicode(cli->conn),
1742
0
           fname_dst_cp,
1743
0
           strlen(fname_dst_cp)+1,
1744
0
           NULL);
1745
0
  if (tevent_req_nomem(bytes, req)) {
1746
0
    return tevent_req_post(req, ev);
1747
0
  }
1748
1749
0
  subreq = cli_smb_send(state, ev, cli, SMBmv, additional_flags,
1750
0
      additional_flags2,
1751
0
      1, state->vwv, talloc_get_size(bytes), bytes);
1752
0
  if (tevent_req_nomem(subreq, req)) {
1753
0
    return tevent_req_post(req, ev);
1754
0
  }
1755
0
  tevent_req_set_callback(subreq, cli_cifs_rename_done, req);
1756
0
  return req;
1757
0
}
1758
1759
static void cli_cifs_rename_done(struct tevent_req *subreq)
1760
0
{
1761
0
  NTSTATUS status = cli_smb_recv(
1762
0
    subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1763
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1764
0
}
1765
1766
static NTSTATUS cli_cifs_rename_recv(struct tevent_req *req)
1767
0
{
1768
0
  return tevent_req_simple_recv_ntstatus(req);
1769
0
}
1770
1771
struct cli_rename_state {
1772
  uint8_t dummy;
1773
};
1774
1775
static void cli_rename_done1(struct tevent_req *subreq);
1776
static void cli_rename_done_cifs(struct tevent_req *subreq);
1777
static void cli_rename_done2(struct tevent_req *subreq);
1778
1779
struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
1780
           struct tevent_context *ev,
1781
           struct cli_state *cli,
1782
           const char *fname_src,
1783
           const char *fname_dst,
1784
           bool replace)
1785
0
{
1786
0
  struct tevent_req *req = NULL, *subreq = NULL;
1787
0
  struct cli_rename_state *state = NULL;
1788
1789
0
  req = tevent_req_create(mem_ctx, &state, struct cli_rename_state);
1790
0
  if (req == NULL) {
1791
0
    return NULL;
1792
0
  }
1793
1794
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1795
0
    subreq = cli_smb2_rename_send(
1796
0
      state, ev, cli, fname_src, fname_dst, replace);
1797
0
    if (tevent_req_nomem(subreq, req)) {
1798
0
      return tevent_req_post(req, ev);
1799
0
    }
1800
0
    tevent_req_set_callback(subreq, cli_rename_done2, req);
1801
0
    return req;
1802
0
  }
1803
1804
0
  if (replace && smbXcli_conn_support_passthrough(cli->conn)) {
1805
0
    subreq = cli_smb1_rename_send(
1806
0
      state, ev, cli, fname_src, fname_dst, replace);
1807
0
    if (tevent_req_nomem(subreq, req)) {
1808
0
      return tevent_req_post(req, ev);
1809
0
    }
1810
0
    tevent_req_set_callback(subreq, cli_rename_done1, req);
1811
0
    return req;
1812
0
  }
1813
1814
0
  subreq = cli_cifs_rename_send(
1815
0
    state, ev, cli, fname_src,fname_dst, replace);
1816
0
  if (tevent_req_nomem(subreq, req)) {
1817
0
    return tevent_req_post(req, ev);
1818
0
  }
1819
0
  tevent_req_set_callback(subreq, cli_rename_done_cifs, req);
1820
0
  return req;
1821
0
}
1822
1823
static void cli_rename_done1(struct tevent_req *subreq)
1824
0
{
1825
0
  NTSTATUS status = cli_smb1_rename_recv(subreq);
1826
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1827
0
}
1828
1829
static void cli_rename_done_cifs(struct tevent_req *subreq)
1830
0
{
1831
0
  NTSTATUS status = cli_cifs_rename_recv(subreq);
1832
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1833
0
}
1834
1835
static void cli_rename_done2(struct tevent_req *subreq)
1836
0
{
1837
0
  NTSTATUS status = cli_smb2_rename_recv(subreq);
1838
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1839
0
}
1840
1841
NTSTATUS cli_rename_recv(struct tevent_req *req)
1842
0
{
1843
0
  return tevent_req_simple_recv_ntstatus(req);
1844
0
}
1845
1846
NTSTATUS cli_rename(struct cli_state *cli,
1847
        const char *fname_src,
1848
        const char *fname_dst,
1849
        bool replace)
1850
0
{
1851
0
  TALLOC_CTX *frame = NULL;
1852
0
  struct tevent_context *ev;
1853
0
  struct tevent_req *req;
1854
0
  NTSTATUS status = NT_STATUS_OK;
1855
1856
0
  frame = talloc_stackframe();
1857
1858
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
1859
    /*
1860
     * Can't use sync call while an async call is in flight
1861
     */
1862
0
    status = NT_STATUS_INVALID_PARAMETER;
1863
0
    goto fail;
1864
0
  }
1865
1866
0
  ev = samba_tevent_context_init(frame);
1867
0
  if (ev == NULL) {
1868
0
    status = NT_STATUS_NO_MEMORY;
1869
0
    goto fail;
1870
0
  }
1871
1872
0
  req = cli_rename_send(frame, ev, cli, fname_src, fname_dst, replace);
1873
0
  if (req == NULL) {
1874
0
    status = NT_STATUS_NO_MEMORY;
1875
0
    goto fail;
1876
0
  }
1877
1878
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1879
0
    goto fail;
1880
0
  }
1881
1882
0
  status = cli_rename_recv(req);
1883
0
 fail:
1884
0
  TALLOC_FREE(frame);
1885
0
  return status;
1886
0
}
1887
1888
/****************************************************************************
1889
 NT Rename a file.
1890
****************************************************************************/
1891
1892
static void cli_ntrename_internal_done(struct tevent_req *subreq);
1893
1894
struct cli_ntrename_internal_state {
1895
  uint16_t vwv[4];
1896
};
1897
1898
static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
1899
        struct tevent_context *ev,
1900
        struct cli_state *cli,
1901
        const char *fname_src,
1902
        const char *fname_dst,
1903
        uint16_t rename_flag)
1904
0
{
1905
0
  struct tevent_req *req = NULL, *subreq = NULL;
1906
0
  struct cli_ntrename_internal_state *state = NULL;
1907
0
  uint8_t additional_flags = 0;
1908
0
  uint16_t additional_flags2 = 0;
1909
0
  uint8_t *bytes = NULL;
1910
0
  char *fname_src_cp = NULL;
1911
0
  char *fname_dst_cp = NULL;
1912
1913
0
  req = tevent_req_create(mem_ctx, &state,
1914
0
        struct cli_ntrename_internal_state);
1915
0
  if (req == NULL) {
1916
0
    return NULL;
1917
0
  }
1918
1919
0
  SSVAL(state->vwv+0, 0 ,FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY);
1920
0
  SSVAL(state->vwv+1, 0, rename_flag);
1921
1922
0
  bytes = talloc_array(state, uint8_t, 1);
1923
0
  if (tevent_req_nomem(bytes, req)) {
1924
0
    return tevent_req_post(req, ev);
1925
0
  }
1926
  /*
1927
   * SMBntrename on a DFS share uses DFS names for src and dst.
1928
   * See smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_rename().
1929
   */
1930
0
  fname_src_cp = smb1_dfs_share_path(state, cli, fname_src);
1931
0
  if (tevent_req_nomem(fname_src_cp, req)) {
1932
0
    return tevent_req_post(req, ev);
1933
0
  }
1934
0
  bytes[0] = 4;
1935
0
  bytes = smb_bytes_push_str(bytes,
1936
0
           smbXcli_conn_use_unicode(cli->conn),
1937
0
           fname_src_cp,
1938
0
           strlen(fname_src_cp)+1,
1939
0
           NULL);
1940
0
  if (tevent_req_nomem(bytes, req)) {
1941
0
    return tevent_req_post(req, ev);
1942
0
  }
1943
1944
0
  if (clistr_is_previous_version_path(fname_src)) {
1945
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
1946
0
  }
1947
1948
0
  bytes = talloc_realloc(state, bytes, uint8_t,
1949
0
      talloc_get_size(bytes)+1);
1950
0
  if (tevent_req_nomem(bytes, req)) {
1951
0
    return tevent_req_post(req, ev);
1952
0
  }
1953
1954
  /*
1955
   * SMBntrename on a DFS share uses DFS names for src and dst.
1956
   * See smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_rename().
1957
   * and smbtorture3: SMB1-DFS-PATHS: test_smb1_ntrename_hardlink()
1958
   */
1959
0
  fname_dst_cp = smb1_dfs_share_path(state, cli, fname_dst);
1960
0
  if (tevent_req_nomem(fname_dst_cp, req)) {
1961
0
    return tevent_req_post(req, ev);
1962
0
  }
1963
0
  bytes[talloc_get_size(bytes)-1] = 4;
1964
0
  bytes = smb_bytes_push_str(bytes,
1965
0
           smbXcli_conn_use_unicode(cli->conn),
1966
0
           fname_dst_cp,
1967
0
           strlen(fname_dst_cp)+1,
1968
0
           NULL);
1969
0
  if (tevent_req_nomem(bytes, req)) {
1970
0
    return tevent_req_post(req, ev);
1971
0
  }
1972
1973
0
  subreq = cli_smb_send(state, ev, cli, SMBntrename, additional_flags,
1974
0
      additional_flags2,
1975
0
      4, state->vwv, talloc_get_size(bytes), bytes);
1976
0
  if (tevent_req_nomem(subreq, req)) {
1977
0
    return tevent_req_post(req, ev);
1978
0
  }
1979
0
  tevent_req_set_callback(subreq, cli_ntrename_internal_done, req);
1980
0
  return req;
1981
0
}
1982
1983
static void cli_ntrename_internal_done(struct tevent_req *subreq)
1984
0
{
1985
0
  NTSTATUS status = cli_smb_recv(
1986
0
    subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
1987
0
  tevent_req_simple_finish_ntstatus(subreq, status);
1988
0
}
1989
1990
static NTSTATUS cli_ntrename_internal_recv(struct tevent_req *req)
1991
0
{
1992
0
  return tevent_req_simple_recv_ntstatus(req);
1993
0
}
1994
1995
struct tevent_req *cli_ntrename_send(TALLOC_CTX *mem_ctx,
1996
        struct tevent_context *ev,
1997
        struct cli_state *cli,
1998
        const char *fname_src,
1999
        const char *fname_dst)
2000
0
{
2001
0
  return cli_ntrename_internal_send(mem_ctx,
2002
0
            ev,
2003
0
            cli,
2004
0
            fname_src,
2005
0
            fname_dst,
2006
0
            RENAME_FLAG_RENAME);
2007
0
}
2008
2009
NTSTATUS cli_ntrename_recv(struct tevent_req *req)
2010
0
{
2011
0
  return cli_ntrename_internal_recv(req);
2012
0
}
2013
2014
NTSTATUS cli_ntrename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
2015
0
{
2016
0
  TALLOC_CTX *frame = talloc_stackframe();
2017
0
  struct tevent_context *ev;
2018
0
  struct tevent_req *req;
2019
0
  NTSTATUS status = NT_STATUS_OK;
2020
2021
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
2022
    /*
2023
     * Can't use sync call while an async call is in flight
2024
     */
2025
0
    status = NT_STATUS_INVALID_PARAMETER;
2026
0
    goto fail;
2027
0
  }
2028
2029
0
  ev = samba_tevent_context_init(frame);
2030
0
  if (ev == NULL) {
2031
0
    status = NT_STATUS_NO_MEMORY;
2032
0
    goto fail;
2033
0
  }
2034
2035
0
  req = cli_ntrename_send(frame, ev, cli, fname_src, fname_dst);
2036
0
  if (req == NULL) {
2037
0
    status = NT_STATUS_NO_MEMORY;
2038
0
    goto fail;
2039
0
  }
2040
2041
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2042
0
    goto fail;
2043
0
  }
2044
2045
0
  status = cli_ntrename_recv(req);
2046
2047
0
 fail:
2048
0
  TALLOC_FREE(frame);
2049
0
  return status;
2050
0
}
2051
2052
/****************************************************************************
2053
 NT hardlink a file.
2054
****************************************************************************/
2055
2056
static struct tevent_req *cli_nt_hardlink_send(TALLOC_CTX *mem_ctx,
2057
        struct tevent_context *ev,
2058
        struct cli_state *cli,
2059
        const char *fname_src,
2060
        const char *fname_dst)
2061
0
{
2062
0
  return cli_ntrename_internal_send(mem_ctx,
2063
0
            ev,
2064
0
            cli,
2065
0
            fname_src,
2066
0
            fname_dst,
2067
0
            RENAME_FLAG_HARD_LINK);
2068
0
}
2069
2070
static NTSTATUS cli_nt_hardlink_recv(struct tevent_req *req)
2071
0
{
2072
0
  return cli_ntrename_internal_recv(req);
2073
0
}
2074
2075
struct cli_smb2_hardlink_state {
2076
  struct tevent_context *ev;
2077
  struct cli_state *cli;
2078
  uint16_t fnum_src;
2079
  const char *fname_dst;
2080
  bool overwrite;
2081
  NTSTATUS status;
2082
};
2083
2084
static void cli_smb2_hardlink_opened(struct tevent_req *subreq);
2085
static void cli_smb2_hardlink_info_set(struct tevent_req *subreq);
2086
static void cli_smb2_hardlink_closed(struct tevent_req *subreq);
2087
2088
static struct tevent_req *cli_smb2_hardlink_send(
2089
  TALLOC_CTX *mem_ctx,
2090
  struct tevent_context *ev,
2091
  struct cli_state *cli,
2092
  const char *fname_src,
2093
  const char *fname_dst,
2094
  bool overwrite,
2095
  struct smb2_create_blobs *in_cblobs)
2096
0
{
2097
0
  struct tevent_req *req = NULL, *subreq = NULL;
2098
0
  struct cli_smb2_hardlink_state *state = NULL;
2099
0
  NTSTATUS status;
2100
2101
0
  req = tevent_req_create(
2102
0
    mem_ctx, &state, struct cli_smb2_hardlink_state);
2103
0
  if (req == NULL) {
2104
0
    return NULL;
2105
0
  }
2106
2107
  /*
2108
   * Strip a MSDFS path from fname_dst if we were given one.
2109
   */
2110
0
  status = cli_dfs_target_check(state,
2111
0
        cli,
2112
0
        fname_dst,
2113
0
        &fname_dst);
2114
0
  if (tevent_req_nterror(req, status)) {
2115
0
    return tevent_req_post(req, ev);
2116
0
  }
2117
2118
0
  state->ev = ev;
2119
0
  state->cli = cli;
2120
0
  state->fname_dst = fname_dst;
2121
0
  state->overwrite = overwrite;
2122
2123
0
  subreq = cli_smb2_create_fnum_send(
2124
0
    state,
2125
0
    ev,
2126
0
    cli,
2127
0
    fname_src,
2128
0
    (struct cli_smb2_create_flags){0},
2129
0
    SMB2_IMPERSONATION_IMPERSONATION,
2130
0
    FILE_WRITE_ATTRIBUTES,
2131
0
    0,      /* file attributes */
2132
0
    FILE_SHARE_READ|
2133
0
    FILE_SHARE_WRITE|
2134
0
    FILE_SHARE_DELETE,  /* share_access */
2135
0
    FILE_OPEN,    /* create_disposition */
2136
0
    FILE_NON_DIRECTORY_FILE, /* no hardlinks on directories */
2137
0
    in_cblobs);
2138
0
  if (tevent_req_nomem(subreq, req)) {
2139
0
    return tevent_req_post(req, ev);
2140
0
  }
2141
0
  tevent_req_set_callback(subreq, cli_smb2_hardlink_opened, req);
2142
0
  return req;
2143
0
}
2144
2145
static void cli_smb2_hardlink_opened(struct tevent_req *subreq)
2146
0
{
2147
0
  struct tevent_req *req = tevent_req_callback_data(
2148
0
    subreq, struct tevent_req);
2149
0
  struct cli_smb2_hardlink_state *state = tevent_req_data(
2150
0
    req, struct cli_smb2_hardlink_state);
2151
0
  NTSTATUS status;
2152
0
  smb_ucs2_t *ucs2_dst;
2153
0
  size_t ucs2_len;
2154
0
  DATA_BLOB inbuf;
2155
0
  bool ok;
2156
2157
0
  status = cli_smb2_create_fnum_recv(
2158
0
    subreq, &state->fnum_src, NULL, NULL, NULL, NULL);
2159
0
  TALLOC_FREE(subreq);
2160
0
  if (tevent_req_nterror(req, status)) {
2161
0
    return;
2162
0
  }
2163
2164
0
  ok = push_ucs2_talloc(state, &ucs2_dst, state->fname_dst, &ucs2_len);
2165
0
  if (!ok || (ucs2_len < 2)) {
2166
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2167
0
    return;
2168
0
  }
2169
  /* Don't 0-terminate the name */
2170
0
  ucs2_len -= 2;
2171
2172
0
  inbuf = data_blob_talloc_zero(state, ucs2_len + 20);
2173
0
  if (tevent_req_nomem(inbuf.data, req)) {
2174
0
    return;
2175
0
  }
2176
2177
0
  if (state->overwrite) {
2178
0
    SCVAL(inbuf.data, 0, 1);
2179
0
  }
2180
0
  SIVAL(inbuf.data, 16, ucs2_len);
2181
0
  memcpy(inbuf.data + 20, ucs2_dst, ucs2_len);
2182
0
  TALLOC_FREE(ucs2_dst);
2183
2184
0
  subreq = cli_smb2_set_info_fnum_send(
2185
0
    state,
2186
0
    state->ev,
2187
0
    state->cli,
2188
0
    state->fnum_src,
2189
0
    SMB2_0_INFO_FILE,     /* in_info_type */
2190
0
    FSCC_FILE_LINK_INFORMATION, /* in_file_info_class */
2191
0
    &inbuf,
2192
0
    0); /* in_additional_info */
2193
0
  if (tevent_req_nomem(subreq, req)) {
2194
0
    return;
2195
0
  }
2196
0
  tevent_req_set_callback(subreq, cli_smb2_hardlink_info_set, req);
2197
0
}
2198
2199
static void cli_smb2_hardlink_info_set(struct tevent_req *subreq)
2200
0
{
2201
0
  struct tevent_req *req = tevent_req_callback_data(
2202
0
    subreq, struct tevent_req);
2203
0
  struct cli_smb2_hardlink_state *state = tevent_req_data(
2204
0
    req, struct cli_smb2_hardlink_state);
2205
2206
0
  state->status = cli_smb2_set_info_fnum_recv(subreq);
2207
0
  TALLOC_FREE(subreq);
2208
2209
  /* ignore error here, we need to close the file */
2210
2211
0
  subreq = cli_smb2_close_fnum_send(state,
2212
0
            state->ev,
2213
0
            state->cli,
2214
0
            state->fnum_src,
2215
0
            0);
2216
0
  if (tevent_req_nomem(subreq, req)) {
2217
0
    return;
2218
0
  }
2219
0
  tevent_req_set_callback(subreq, cli_smb2_hardlink_closed, req);
2220
0
}
2221
2222
static void cli_smb2_hardlink_closed(struct tevent_req *subreq)
2223
0
{
2224
0
  NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
2225
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2226
0
}
2227
2228
static NTSTATUS cli_smb2_hardlink_recv(struct tevent_req *req)
2229
0
{
2230
0
  struct cli_smb2_hardlink_state *state = tevent_req_data(
2231
0
    req, struct cli_smb2_hardlink_state);
2232
0
  NTSTATUS status;
2233
2234
0
  if (tevent_req_is_nterror(req, &status)) {
2235
0
    return status;
2236
0
  }
2237
0
  return state->status;
2238
0
}
2239
2240
struct cli_hardlink_state {
2241
  uint8_t dummy;
2242
};
2243
2244
static void cli_hardlink_done(struct tevent_req *subreq);
2245
static void cli_hardlink_done2(struct tevent_req *subreq);
2246
2247
struct tevent_req *cli_hardlink_send(
2248
  TALLOC_CTX *mem_ctx,
2249
  struct tevent_context *ev,
2250
  struct cli_state *cli,
2251
  const char *fname_src,
2252
  const char *fname_dst)
2253
0
{
2254
0
  struct tevent_req *req = NULL, *subreq = NULL;
2255
0
  struct cli_hardlink_state *state;
2256
2257
0
  req = tevent_req_create(mem_ctx, &state, struct cli_hardlink_state);
2258
0
  if (req == NULL) {
2259
0
    return NULL;
2260
0
  }
2261
2262
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2263
0
    subreq = cli_smb2_hardlink_send(
2264
0
      state, ev, cli, fname_src, fname_dst, false, NULL);
2265
0
    if (tevent_req_nomem(subreq, req)) {
2266
0
      return tevent_req_post(req, ev);
2267
0
    }
2268
0
    tevent_req_set_callback(subreq, cli_hardlink_done2, req);
2269
0
    return req;
2270
0
  }
2271
2272
0
  subreq = cli_nt_hardlink_send(state, ev, cli, fname_src, fname_dst);
2273
0
  if (tevent_req_nomem(subreq, req)) {
2274
0
    return tevent_req_post(req, ev);
2275
0
  }
2276
0
  tevent_req_set_callback(subreq, cli_hardlink_done, req);
2277
0
  return req;
2278
0
}
2279
2280
static void cli_hardlink_done(struct tevent_req *subreq)
2281
0
{
2282
0
  NTSTATUS status = cli_nt_hardlink_recv(subreq);
2283
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2284
0
}
2285
2286
static void cli_hardlink_done2(struct tevent_req *subreq)
2287
0
{
2288
0
  NTSTATUS status = cli_smb2_hardlink_recv(subreq);
2289
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2290
0
}
2291
2292
NTSTATUS cli_hardlink_recv(struct tevent_req *req)
2293
0
{
2294
0
  return tevent_req_simple_recv_ntstatus(req);
2295
0
}
2296
2297
NTSTATUS cli_hardlink(
2298
  struct cli_state *cli, const char *fname_src, const char *fname_dst)
2299
0
{
2300
0
  TALLOC_CTX *frame = talloc_stackframe();
2301
0
  struct tevent_context *ev = NULL;
2302
0
  struct tevent_req *req = NULL;
2303
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
2304
2305
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
2306
0
    status = NT_STATUS_INVALID_PARAMETER;
2307
0
    goto fail;
2308
0
  }
2309
0
  ev = samba_tevent_context_init(frame);
2310
0
  if (ev == NULL) {
2311
0
    goto fail;
2312
0
  }
2313
0
  req = cli_hardlink_send(frame, ev, cli, fname_src, fname_dst);
2314
0
  if (req == NULL) {
2315
0
    goto fail;
2316
0
  }
2317
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2318
0
    goto fail;
2319
0
  }
2320
0
  status = cli_hardlink_recv(req);
2321
0
 fail:
2322
0
  TALLOC_FREE(frame);
2323
0
  return status;
2324
0
}
2325
2326
/****************************************************************************
2327
 Delete a file.
2328
****************************************************************************/
2329
2330
static void cli_unlink_done(struct tevent_req *subreq);
2331
static void cli_unlink_done2(struct tevent_req *subreq);
2332
2333
struct cli_unlink_state {
2334
  uint16_t vwv[1];
2335
};
2336
2337
struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
2338
        struct tevent_context *ev,
2339
        struct cli_state *cli,
2340
        const char *fname,
2341
        uint32_t mayhave_attrs)
2342
0
{
2343
0
  struct tevent_req *req = NULL, *subreq = NULL;
2344
0
  struct cli_unlink_state *state = NULL;
2345
0
  uint8_t additional_flags = 0;
2346
0
  uint16_t additional_flags2 = 0;
2347
0
  uint8_t *bytes = NULL;
2348
0
  char *fname_cp = NULL;
2349
2350
0
  req = tevent_req_create(mem_ctx, &state, struct cli_unlink_state);
2351
0
  if (req == NULL) {
2352
0
    return NULL;
2353
0
  }
2354
2355
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2356
0
    subreq = cli_smb2_unlink_send(state, ev, cli, fname, NULL);
2357
0
    if (tevent_req_nomem(subreq, req)) {
2358
0
      return tevent_req_post(req, ev);
2359
0
    }
2360
0
    tevent_req_set_callback(subreq, cli_unlink_done2, req);
2361
0
    return req;
2362
0
  }
2363
2364
0
  if (mayhave_attrs & 0xFFFF0000) {
2365
    /*
2366
     * Don't allow attributes greater than
2367
     * 16-bits for a 16-bit protocol value.
2368
     */
2369
0
    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
2370
0
    return tevent_req_post(req, ev);
2371
0
  }
2372
2373
0
  SSVAL(state->vwv+0, 0, mayhave_attrs);
2374
2375
0
  bytes = talloc_array(state, uint8_t, 1);
2376
0
  if (tevent_req_nomem(bytes, req)) {
2377
0
    return tevent_req_post(req, ev);
2378
0
  }
2379
  /*
2380
   * SMBunlink on a DFS share must use DFS names.
2381
   */
2382
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
2383
0
  if (tevent_req_nomem(fname_cp, req)) {
2384
0
    return tevent_req_post(req, ev);
2385
0
  }
2386
0
  bytes[0] = 4;
2387
0
  bytes = smb_bytes_push_str(bytes,
2388
0
           smbXcli_conn_use_unicode(cli->conn),
2389
0
           fname_cp,
2390
0
           strlen(fname_cp)+1,
2391
0
           NULL);
2392
2393
0
  if (tevent_req_nomem(bytes, req)) {
2394
0
    return tevent_req_post(req, ev);
2395
0
  }
2396
2397
0
  if (clistr_is_previous_version_path(fname)) {
2398
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
2399
0
  }
2400
2401
0
  subreq = cli_smb_send(state, ev, cli, SMBunlink, additional_flags,
2402
0
        additional_flags2,
2403
0
        1, state->vwv, talloc_get_size(bytes), bytes);
2404
0
  if (tevent_req_nomem(subreq, req)) {
2405
0
    return tevent_req_post(req, ev);
2406
0
  }
2407
0
  tevent_req_set_callback(subreq, cli_unlink_done, req);
2408
0
  return req;
2409
0
}
2410
2411
static void cli_unlink_done(struct tevent_req *subreq)
2412
0
{
2413
0
  NTSTATUS status = cli_smb_recv(
2414
0
    subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2415
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2416
0
}
2417
2418
static void cli_unlink_done2(struct tevent_req *subreq)
2419
0
{
2420
0
  NTSTATUS status = cli_smb2_unlink_recv(subreq);
2421
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2422
0
}
2423
2424
NTSTATUS cli_unlink_recv(struct tevent_req *req)
2425
0
{
2426
0
  return tevent_req_simple_recv_ntstatus(req);
2427
0
}
2428
2429
NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint32_t mayhave_attrs)
2430
0
{
2431
0
  TALLOC_CTX *frame = NULL;
2432
0
  struct tevent_context *ev;
2433
0
  struct tevent_req *req;
2434
0
  NTSTATUS status = NT_STATUS_OK;
2435
2436
0
  frame = talloc_stackframe();
2437
2438
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
2439
    /*
2440
     * Can't use sync call while an async call is in flight
2441
     */
2442
0
    status = NT_STATUS_INVALID_PARAMETER;
2443
0
    goto fail;
2444
0
  }
2445
2446
0
  ev = samba_tevent_context_init(frame);
2447
0
  if (ev == NULL) {
2448
0
    status = NT_STATUS_NO_MEMORY;
2449
0
    goto fail;
2450
0
  }
2451
2452
0
  req = cli_unlink_send(frame, ev, cli, fname, mayhave_attrs);
2453
0
  if (req == NULL) {
2454
0
    status = NT_STATUS_NO_MEMORY;
2455
0
    goto fail;
2456
0
  }
2457
2458
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2459
0
    goto fail;
2460
0
  }
2461
2462
0
  status = cli_unlink_recv(req);
2463
0
 fail:
2464
0
  TALLOC_FREE(frame);
2465
0
  return status;
2466
0
}
2467
2468
/****************************************************************************
2469
 Create a directory.
2470
****************************************************************************/
2471
2472
static void cli_mkdir_done(struct tevent_req *subreq);
2473
static void cli_mkdir_done2(struct tevent_req *subreq);
2474
2475
struct cli_mkdir_state {
2476
  int dummy;
2477
};
2478
2479
struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
2480
          struct tevent_context *ev,
2481
          struct cli_state *cli,
2482
          const char *dname)
2483
0
{
2484
0
  struct tevent_req *req = NULL, *subreq = NULL;
2485
0
  struct cli_mkdir_state *state = NULL;
2486
0
  uint8_t additional_flags = 0;
2487
0
  uint16_t additional_flags2 = 0;
2488
0
  uint8_t *bytes = NULL;
2489
0
  char *dname_cp = NULL;
2490
2491
0
  req = tevent_req_create(mem_ctx, &state, struct cli_mkdir_state);
2492
0
  if (req == NULL) {
2493
0
    return NULL;
2494
0
  }
2495
2496
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2497
0
    subreq = cli_smb2_mkdir_send(state, ev, cli, dname);
2498
0
    if (tevent_req_nomem(subreq, req)) {
2499
0
      return tevent_req_post(req, ev);
2500
0
    }
2501
0
    tevent_req_set_callback(subreq, cli_mkdir_done2, req);
2502
0
    return req;
2503
0
  }
2504
2505
0
  bytes = talloc_array(state, uint8_t, 1);
2506
0
  if (tevent_req_nomem(bytes, req)) {
2507
0
    return tevent_req_post(req, ev);
2508
0
  }
2509
  /*
2510
   * SMBmkdir on a DFS share must use DFS names.
2511
   */
2512
0
  dname_cp = smb1_dfs_share_path(state, cli, dname);
2513
0
  if (tevent_req_nomem(dname_cp, req)) {
2514
0
    return tevent_req_post(req, ev);
2515
0
  }
2516
0
  bytes[0] = 4;
2517
0
  bytes = smb_bytes_push_str(bytes,
2518
0
           smbXcli_conn_use_unicode(cli->conn),
2519
0
           dname_cp,
2520
0
           strlen(dname_cp)+1,
2521
0
           NULL);
2522
2523
0
  if (tevent_req_nomem(bytes, req)) {
2524
0
    return tevent_req_post(req, ev);
2525
0
  }
2526
2527
0
  if (clistr_is_previous_version_path(dname)) {
2528
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
2529
0
  }
2530
2531
0
  subreq = cli_smb_send(state, ev, cli, SMBmkdir, additional_flags,
2532
0
      additional_flags2,
2533
0
      0, NULL, talloc_get_size(bytes), bytes);
2534
0
  if (tevent_req_nomem(subreq, req)) {
2535
0
    return tevent_req_post(req, ev);
2536
0
  }
2537
0
  tevent_req_set_callback(subreq, cli_mkdir_done, req);
2538
0
  return req;
2539
0
}
2540
2541
static void cli_mkdir_done(struct tevent_req *subreq)
2542
0
{
2543
0
  struct tevent_req *req = tevent_req_callback_data(
2544
0
    subreq, struct tevent_req);
2545
0
  NTSTATUS status;
2546
2547
0
  status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2548
0
  TALLOC_FREE(subreq);
2549
0
  if (tevent_req_nterror(req, status)) {
2550
0
    return;
2551
0
  }
2552
0
  tevent_req_done(req);
2553
0
}
2554
2555
static void cli_mkdir_done2(struct tevent_req *subreq)
2556
0
{
2557
0
  NTSTATUS status = cli_smb2_mkdir_recv(subreq);
2558
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2559
0
}
2560
2561
NTSTATUS cli_mkdir_recv(struct tevent_req *req)
2562
0
{
2563
0
  return tevent_req_simple_recv_ntstatus(req);
2564
0
}
2565
2566
NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname)
2567
0
{
2568
0
  TALLOC_CTX *frame = NULL;
2569
0
  struct tevent_context *ev;
2570
0
  struct tevent_req *req;
2571
0
  NTSTATUS status = NT_STATUS_OK;
2572
2573
0
  frame = talloc_stackframe();
2574
2575
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
2576
    /*
2577
     * Can't use sync call while an async call is in flight
2578
     */
2579
0
    status = NT_STATUS_INVALID_PARAMETER;
2580
0
    goto fail;
2581
0
  }
2582
2583
0
  ev = samba_tevent_context_init(frame);
2584
0
  if (ev == NULL) {
2585
0
    status = NT_STATUS_NO_MEMORY;
2586
0
    goto fail;
2587
0
  }
2588
2589
0
  req = cli_mkdir_send(frame, ev, cli, dname);
2590
0
  if (req == NULL) {
2591
0
    status = NT_STATUS_NO_MEMORY;
2592
0
    goto fail;
2593
0
  }
2594
2595
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2596
0
    goto fail;
2597
0
  }
2598
2599
0
  status = cli_mkdir_recv(req);
2600
0
 fail:
2601
0
  TALLOC_FREE(frame);
2602
0
  return status;
2603
0
}
2604
2605
/****************************************************************************
2606
 Remove a directory.
2607
****************************************************************************/
2608
2609
static void cli_rmdir_done(struct tevent_req *subreq);
2610
static void cli_rmdir_done2(struct tevent_req *subreq);
2611
2612
struct cli_rmdir_state {
2613
  int dummy;
2614
};
2615
2616
struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
2617
          struct tevent_context *ev,
2618
          struct cli_state *cli,
2619
          const char *dname)
2620
0
{
2621
0
  struct tevent_req *req = NULL, *subreq = NULL;
2622
0
  struct cli_rmdir_state *state = NULL;
2623
0
  uint8_t additional_flags = 0;
2624
0
  uint16_t additional_flags2 = 0;
2625
0
  uint8_t *bytes = NULL;
2626
0
  char *dname_cp = NULL;
2627
2628
0
  req = tevent_req_create(mem_ctx, &state, struct cli_rmdir_state);
2629
0
  if (req == NULL) {
2630
0
    return NULL;
2631
0
  }
2632
2633
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2634
0
    subreq = cli_smb2_rmdir_send(state, ev, cli, dname, NULL);
2635
0
    if (tevent_req_nomem(subreq, req)) {
2636
0
      return tevent_req_post(req, ev);
2637
0
    }
2638
0
    tevent_req_set_callback(subreq, cli_rmdir_done2, req);
2639
0
    return req;
2640
0
  }
2641
2642
0
  bytes = talloc_array(state, uint8_t, 1);
2643
0
  if (tevent_req_nomem(bytes, req)) {
2644
0
    return tevent_req_post(req, ev);
2645
0
  }
2646
  /*
2647
   * SMBrmdir on a DFS share must use DFS names.
2648
   */
2649
0
  dname_cp = smb1_dfs_share_path(state, cli, dname);
2650
0
  if (tevent_req_nomem(dname_cp, req)) {
2651
0
    return tevent_req_post(req, ev);
2652
0
  }
2653
0
  bytes[0] = 4;
2654
0
  bytes = smb_bytes_push_str(bytes,
2655
0
           smbXcli_conn_use_unicode(cli->conn),
2656
0
           dname_cp,
2657
0
           strlen(dname_cp)+1,
2658
0
           NULL);
2659
2660
0
  if (tevent_req_nomem(bytes, req)) {
2661
0
    return tevent_req_post(req, ev);
2662
0
  }
2663
2664
0
  if (clistr_is_previous_version_path(dname)) {
2665
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
2666
0
  }
2667
2668
0
  subreq = cli_smb_send(state, ev, cli, SMBrmdir, additional_flags,
2669
0
      additional_flags2,
2670
0
      0, NULL, talloc_get_size(bytes), bytes);
2671
0
  if (tevent_req_nomem(subreq, req)) {
2672
0
    return tevent_req_post(req, ev);
2673
0
  }
2674
0
  tevent_req_set_callback(subreq, cli_rmdir_done, req);
2675
0
  return req;
2676
0
}
2677
2678
static void cli_rmdir_done(struct tevent_req *subreq)
2679
0
{
2680
0
  NTSTATUS status = cli_smb_recv(
2681
0
    subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2682
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2683
0
}
2684
2685
static void cli_rmdir_done2(struct tevent_req *subreq)
2686
0
{
2687
0
  NTSTATUS status = cli_smb2_rmdir_recv(subreq);
2688
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2689
0
}
2690
2691
NTSTATUS cli_rmdir_recv(struct tevent_req *req)
2692
0
{
2693
0
  return tevent_req_simple_recv_ntstatus(req);
2694
0
}
2695
2696
NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname)
2697
0
{
2698
0
  TALLOC_CTX *frame = NULL;
2699
0
  struct tevent_context *ev;
2700
0
  struct tevent_req *req;
2701
0
  NTSTATUS status = NT_STATUS_OK;
2702
2703
0
  frame = talloc_stackframe();
2704
2705
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
2706
    /*
2707
     * Can't use sync call while an async call is in flight
2708
     */
2709
0
    status = NT_STATUS_INVALID_PARAMETER;
2710
0
    goto fail;
2711
0
  }
2712
2713
0
  ev = samba_tevent_context_init(frame);
2714
0
  if (ev == NULL) {
2715
0
    status = NT_STATUS_NO_MEMORY;
2716
0
    goto fail;
2717
0
  }
2718
2719
0
  req = cli_rmdir_send(frame, ev, cli, dname);
2720
0
  if (req == NULL) {
2721
0
    status = NT_STATUS_NO_MEMORY;
2722
0
    goto fail;
2723
0
  }
2724
2725
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2726
0
    goto fail;
2727
0
  }
2728
2729
0
  status = cli_rmdir_recv(req);
2730
0
 fail:
2731
0
  TALLOC_FREE(frame);
2732
0
  return status;
2733
0
}
2734
2735
/****************************************************************************
2736
 Set or clear the delete on close flag.
2737
****************************************************************************/
2738
2739
struct doc_state {
2740
  uint8_t data[1];
2741
};
2742
2743
static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq);
2744
static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq);
2745
2746
struct tevent_req *cli_nt_delete_on_close_send(TALLOC_CTX *mem_ctx,
2747
          struct tevent_context *ev,
2748
          struct cli_state *cli,
2749
          uint16_t fnum,
2750
          bool flag)
2751
0
{
2752
0
  struct tevent_req *req = NULL, *subreq = NULL;
2753
0
  struct doc_state *state = NULL;
2754
2755
0
  req = tevent_req_create(mem_ctx, &state, struct doc_state);
2756
0
  if (req == NULL) {
2757
0
    return NULL;
2758
0
  }
2759
2760
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2761
0
    subreq = cli_smb2_delete_on_close_send(state, ev, cli,
2762
0
                   fnum, flag);
2763
0
    if (tevent_req_nomem(subreq, req)) {
2764
0
      return tevent_req_post(req, ev);
2765
0
    }
2766
0
    tevent_req_set_callback(subreq,
2767
0
          cli_nt_delete_on_close_smb2_done,
2768
0
          req);
2769
0
    return req;
2770
0
  }
2771
2772
  /* Setup data array. */
2773
0
  SCVAL(&state->data[0], 0, flag ? 1 : 0);
2774
2775
0
  subreq = cli_setfileinfo_send(
2776
0
    state,
2777
0
    ev,
2778
0
    cli,
2779
0
    fnum,
2780
0
    SMB_SET_FILE_DISPOSITION_INFO,
2781
0
    state->data,
2782
0
    sizeof(state->data));
2783
2784
0
  if (tevent_req_nomem(subreq, req)) {
2785
0
    return tevent_req_post(req, ev);
2786
0
  }
2787
0
  tevent_req_set_callback(subreq,
2788
0
        cli_nt_delete_on_close_smb1_done,
2789
0
        req);
2790
0
  return req;
2791
0
}
2792
2793
static void cli_nt_delete_on_close_smb1_done(struct tevent_req *subreq)
2794
0
{
2795
0
  NTSTATUS status = cli_setfileinfo_recv(subreq);
2796
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2797
0
}
2798
2799
static void cli_nt_delete_on_close_smb2_done(struct tevent_req *subreq)
2800
0
{
2801
0
  NTSTATUS status = cli_smb2_delete_on_close_recv(subreq);
2802
0
  tevent_req_simple_finish_ntstatus(subreq, status);
2803
0
}
2804
2805
NTSTATUS cli_nt_delete_on_close_recv(struct tevent_req *req)
2806
0
{
2807
0
  return tevent_req_simple_recv_ntstatus(req);
2808
0
}
2809
2810
NTSTATUS cli_nt_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
2811
0
{
2812
0
  TALLOC_CTX *frame = talloc_stackframe();
2813
0
  struct tevent_context *ev = NULL;
2814
0
  struct tevent_req *req = NULL;
2815
0
  NTSTATUS status = NT_STATUS_OK;
2816
2817
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
2818
    /*
2819
     * Can't use sync call while an async call is in flight
2820
     */
2821
0
    status = NT_STATUS_INVALID_PARAMETER;
2822
0
    goto fail;
2823
0
  }
2824
2825
0
  ev = samba_tevent_context_init(frame);
2826
0
  if (ev == NULL) {
2827
0
    status = NT_STATUS_NO_MEMORY;
2828
0
    goto fail;
2829
0
  }
2830
2831
0
  req = cli_nt_delete_on_close_send(frame,
2832
0
        ev,
2833
0
        cli,
2834
0
        fnum,
2835
0
        flag);
2836
0
  if (req == NULL) {
2837
0
    status = NT_STATUS_NO_MEMORY;
2838
0
    goto fail;
2839
0
  }
2840
2841
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2842
0
    goto fail;
2843
0
  }
2844
2845
0
  status = cli_nt_delete_on_close_recv(req);
2846
2847
0
 fail:
2848
0
  TALLOC_FREE(frame);
2849
0
  return status;
2850
0
}
2851
2852
struct cli_ntcreate1_state {
2853
  uint16_t vwv[24];
2854
  uint16_t fnum;
2855
  struct smb_create_returns cr;
2856
  struct tevent_req *subreq;
2857
};
2858
2859
static void cli_ntcreate1_done(struct tevent_req *subreq);
2860
static bool cli_ntcreate1_cancel(struct tevent_req *req);
2861
2862
static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
2863
               struct tevent_context *ev,
2864
               struct cli_state *cli,
2865
               const char *fname,
2866
               uint32_t CreatFlags,
2867
               uint32_t DesiredAccess,
2868
               uint32_t FileAttributes,
2869
               uint32_t ShareAccess,
2870
               uint32_t CreateDisposition,
2871
               uint32_t CreateOptions,
2872
               uint32_t ImpersonationLevel,
2873
               uint8_t SecurityFlags)
2874
0
{
2875
0
  struct tevent_req *req, *subreq;
2876
0
  struct cli_ntcreate1_state *state;
2877
0
  uint16_t *vwv;
2878
0
  uint8_t *bytes;
2879
0
  size_t converted_len;
2880
0
  uint16_t additional_flags2 = 0;
2881
0
  char *fname_cp = NULL;
2882
2883
0
  req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate1_state);
2884
0
  if (req == NULL) {
2885
0
    return NULL;
2886
0
  }
2887
2888
0
  vwv = state->vwv;
2889
2890
0
  SCVAL(vwv+0, 0, 0xFF);
2891
0
  SCVAL(vwv+0, 1, 0);
2892
0
  SSVAL(vwv+1, 0, 0);
2893
0
  SCVAL(vwv+2, 0, 0);
2894
2895
0
  if (cli->use_oplocks) {
2896
0
    CreatFlags |= (REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK);
2897
0
  }
2898
0
  SIVAL(vwv+3, 1, CreatFlags);
2899
0
  SIVAL(vwv+5, 1, 0x0);  /* RootDirectoryFid */
2900
0
  SIVAL(vwv+7, 1, DesiredAccess);
2901
0
  SIVAL(vwv+9, 1, 0x0);  /* AllocationSize */
2902
0
  SIVAL(vwv+11, 1, 0x0); /* AllocationSize */
2903
0
  SIVAL(vwv+13, 1, FileAttributes);
2904
0
  SIVAL(vwv+15, 1, ShareAccess);
2905
0
  SIVAL(vwv+17, 1, CreateDisposition);
2906
0
  SIVAL(vwv+19, 1, CreateOptions |
2907
0
    (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
2908
0
  SIVAL(vwv+21, 1, ImpersonationLevel);
2909
0
  SCVAL(vwv+23, 1, SecurityFlags);
2910
2911
0
  bytes = talloc_array(state, uint8_t, 0);
2912
0
  if (tevent_req_nomem(bytes, req)) {
2913
0
    return tevent_req_post(req, ev);
2914
0
  }
2915
  /*
2916
   * SMBntcreateX on a DFS share must use DFS names.
2917
   */
2918
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
2919
0
  if (tevent_req_nomem(fname_cp, req)) {
2920
0
    return tevent_req_post(req, ev);
2921
0
  }
2922
0
  bytes = smb_bytes_push_str(bytes,
2923
0
           smbXcli_conn_use_unicode(cli->conn),
2924
0
           fname_cp,
2925
0
           strlen(fname_cp)+1,
2926
0
           &converted_len);
2927
0
  if (tevent_req_nomem(bytes, req)) {
2928
0
    return tevent_req_post(req, ev);
2929
0
  }
2930
2931
0
  if (clistr_is_previous_version_path(fname)) {
2932
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
2933
0
  }
2934
2935
  /* sigh. this copes with broken netapp filer behaviour */
2936
0
  bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, NULL);
2937
2938
0
  if (tevent_req_nomem(bytes, req)) {
2939
0
    return tevent_req_post(req, ev);
2940
0
  }
2941
2942
0
  SSVAL(vwv+2, 1, converted_len);
2943
2944
0
  subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0,
2945
0
      additional_flags2, 24, vwv,
2946
0
      talloc_get_size(bytes), bytes);
2947
0
  if (tevent_req_nomem(subreq, req)) {
2948
0
    return tevent_req_post(req, ev);
2949
0
  }
2950
0
  tevent_req_set_callback(subreq, cli_ntcreate1_done, req);
2951
2952
0
  state->subreq = subreq;
2953
0
  tevent_req_set_cancel_fn(req, cli_ntcreate1_cancel);
2954
2955
0
  return req;
2956
0
}
2957
2958
static void cli_ntcreate1_done(struct tevent_req *subreq)
2959
0
{
2960
0
  struct tevent_req *req = tevent_req_callback_data(
2961
0
    subreq, struct tevent_req);
2962
0
  struct cli_ntcreate1_state *state = tevent_req_data(
2963
0
    req, struct cli_ntcreate1_state);
2964
0
  uint8_t wct;
2965
0
  uint16_t *vwv;
2966
0
  uint32_t num_bytes;
2967
0
  uint8_t *bytes;
2968
0
  NTSTATUS status;
2969
2970
0
  status = cli_smb_recv(subreq, state, NULL, 34, &wct, &vwv,
2971
0
            &num_bytes, &bytes);
2972
0
  TALLOC_FREE(subreq);
2973
0
  if (tevent_req_nterror(req, status)) {
2974
0
    return;
2975
0
  }
2976
0
  state->cr.oplock_level = CVAL(vwv+2, 0);
2977
0
  state->fnum = SVAL(vwv+2, 1);
2978
0
  state->cr.create_action = IVAL(vwv+3, 1);
2979
0
  state->cr.creation_time = BVAL(vwv+5, 1);
2980
0
  state->cr.last_access_time = BVAL(vwv+9, 1);
2981
0
  state->cr.last_write_time = BVAL(vwv+13, 1);
2982
0
  state->cr.change_time   = BVAL(vwv+17, 1);
2983
0
  state->cr.file_attributes = IVAL(vwv+21, 1);
2984
0
  state->cr.allocation_size = BVAL(vwv+23, 1);
2985
0
  state->cr.end_of_file   = BVAL(vwv+27, 1);
2986
2987
0
  tevent_req_done(req);
2988
0
}
2989
2990
static bool cli_ntcreate1_cancel(struct tevent_req *req)
2991
0
{
2992
0
  struct cli_ntcreate1_state *state = tevent_req_data(
2993
0
    req, struct cli_ntcreate1_state);
2994
0
  return tevent_req_cancel(state->subreq);
2995
0
}
2996
2997
static NTSTATUS cli_ntcreate1_recv(struct tevent_req *req,
2998
           uint16_t *pfnum,
2999
           struct smb_create_returns *cr)
3000
0
{
3001
0
  struct cli_ntcreate1_state *state = tevent_req_data(
3002
0
    req, struct cli_ntcreate1_state);
3003
0
  NTSTATUS status;
3004
3005
0
  if (tevent_req_is_nterror(req, &status)) {
3006
0
    return status;
3007
0
  }
3008
0
  *pfnum = state->fnum;
3009
0
  if (cr != NULL) {
3010
0
    *cr = state->cr;
3011
0
  }
3012
0
  return NT_STATUS_OK;
3013
0
}
3014
3015
struct cli_ntcreate_state {
3016
  struct smb_create_returns cr;
3017
  uint16_t fnum;
3018
  struct tevent_req *subreq;
3019
};
3020
3021
static void cli_ntcreate_done_nt1(struct tevent_req *subreq);
3022
static void cli_ntcreate_done_smb2(struct tevent_req *subreq);
3023
static bool cli_ntcreate_cancel(struct tevent_req *req);
3024
3025
struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx,
3026
             struct tevent_context *ev,
3027
             struct cli_state *cli,
3028
             const char *fname,
3029
             uint32_t create_flags,
3030
             uint32_t desired_access,
3031
             uint32_t file_attributes,
3032
             uint32_t share_access,
3033
             uint32_t create_disposition,
3034
             uint32_t create_options,
3035
             uint32_t impersonation_level,
3036
             uint8_t security_flags)
3037
0
{
3038
0
  struct tevent_req *req, *subreq;
3039
0
  struct cli_ntcreate_state *state;
3040
3041
0
  req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state);
3042
0
  if (req == NULL) {
3043
0
    return NULL;
3044
0
  }
3045
3046
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3047
0
    struct cli_smb2_create_flags cflags = {0};
3048
3049
0
    if (cli->use_oplocks) {
3050
0
      create_flags |= REQUEST_OPLOCK|REQUEST_BATCH_OPLOCK;
3051
0
    }
3052
3053
0
    cflags = (struct cli_smb2_create_flags) {
3054
0
      .batch_oplock = (create_flags & REQUEST_BATCH_OPLOCK),
3055
0
      .exclusive_oplock = (create_flags & REQUEST_OPLOCK),
3056
0
    };
3057
3058
0
    subreq = cli_smb2_create_fnum_send(
3059
0
      state,
3060
0
      ev,
3061
0
      cli,
3062
0
      fname,
3063
0
      cflags,
3064
0
      impersonation_level,
3065
0
      desired_access,
3066
0
      file_attributes,
3067
0
      share_access,
3068
0
      create_disposition,
3069
0
      create_options,
3070
0
      NULL);
3071
0
    if (tevent_req_nomem(subreq, req)) {
3072
0
      return tevent_req_post(req, ev);
3073
0
    }
3074
0
    tevent_req_set_callback(subreq, cli_ntcreate_done_smb2, req);
3075
0
  } else {
3076
0
    subreq = cli_ntcreate1_send(
3077
0
      state, ev, cli, fname, create_flags, desired_access,
3078
0
      file_attributes, share_access, create_disposition,
3079
0
      create_options, impersonation_level, security_flags);
3080
0
    if (tevent_req_nomem(subreq, req)) {
3081
0
      return tevent_req_post(req, ev);
3082
0
    }
3083
0
    tevent_req_set_callback(subreq, cli_ntcreate_done_nt1, req);
3084
0
  }
3085
3086
0
  state->subreq = subreq;
3087
0
  tevent_req_set_cancel_fn(req, cli_ntcreate_cancel);
3088
3089
0
  return req;
3090
0
}
3091
3092
static void cli_ntcreate_done_nt1(struct tevent_req *subreq)
3093
0
{
3094
0
  struct tevent_req *req = tevent_req_callback_data(
3095
0
    subreq, struct tevent_req);
3096
0
  struct cli_ntcreate_state *state = tevent_req_data(
3097
0
    req, struct cli_ntcreate_state);
3098
0
  NTSTATUS status;
3099
3100
0
  status = cli_ntcreate1_recv(subreq, &state->fnum, &state->cr);
3101
0
  TALLOC_FREE(subreq);
3102
0
  if (tevent_req_nterror(req, status)) {
3103
0
    return;
3104
0
  }
3105
0
  tevent_req_done(req);
3106
0
}
3107
3108
static void cli_ntcreate_done_smb2(struct tevent_req *subreq)
3109
0
{
3110
0
  struct tevent_req *req = tevent_req_callback_data(
3111
0
    subreq, struct tevent_req);
3112
0
  struct cli_ntcreate_state *state = tevent_req_data(
3113
0
    req, struct cli_ntcreate_state);
3114
0
  NTSTATUS status;
3115
3116
0
  status = cli_smb2_create_fnum_recv(
3117
0
    subreq,
3118
0
    &state->fnum,
3119
0
    &state->cr,
3120
0
    NULL,
3121
0
    NULL,
3122
0
    NULL);
3123
0
  TALLOC_FREE(subreq);
3124
0
  if (tevent_req_nterror(req, status)) {
3125
0
    return;
3126
0
  }
3127
0
  tevent_req_done(req);
3128
0
}
3129
3130
static bool cli_ntcreate_cancel(struct tevent_req *req)
3131
0
{
3132
0
  struct cli_ntcreate_state *state = tevent_req_data(
3133
0
    req, struct cli_ntcreate_state);
3134
0
  return tevent_req_cancel(state->subreq);
3135
0
}
3136
3137
NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *fnum,
3138
         struct smb_create_returns *cr)
3139
0
{
3140
0
  struct cli_ntcreate_state *state = tevent_req_data(
3141
0
    req, struct cli_ntcreate_state);
3142
0
  NTSTATUS status;
3143
3144
0
  if (tevent_req_is_nterror(req, &status)) {
3145
0
    return status;
3146
0
  }
3147
0
  if (fnum != NULL) {
3148
0
    *fnum = state->fnum;
3149
0
  }
3150
0
  if (cr != NULL) {
3151
0
    *cr = state->cr;
3152
0
  }
3153
0
  return NT_STATUS_OK;
3154
0
}
3155
3156
NTSTATUS cli_ntcreate(struct cli_state *cli,
3157
          const char *fname,
3158
          uint32_t CreatFlags,
3159
          uint32_t DesiredAccess,
3160
          uint32_t FileAttributes,
3161
          uint32_t ShareAccess,
3162
          uint32_t CreateDisposition,
3163
          uint32_t CreateOptions,
3164
          uint8_t SecurityFlags,
3165
          uint16_t *pfid,
3166
          struct smb_create_returns *cr)
3167
0
{
3168
0
  TALLOC_CTX *frame = talloc_stackframe();
3169
0
  struct tevent_context *ev;
3170
0
  struct tevent_req *req;
3171
0
  uint32_t ImpersonationLevel = SMB2_IMPERSONATION_IMPERSONATION;
3172
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
3173
3174
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
3175
    /*
3176
     * Can't use sync call while an async call is in flight
3177
     */
3178
0
    status = NT_STATUS_INVALID_PARAMETER;
3179
0
    goto fail;
3180
0
  }
3181
3182
0
  ev = samba_tevent_context_init(frame);
3183
0
  if (ev == NULL) {
3184
0
    goto fail;
3185
0
  }
3186
3187
0
  req = cli_ntcreate_send(frame, ev, cli, fname, CreatFlags,
3188
0
        DesiredAccess, FileAttributes, ShareAccess,
3189
0
        CreateDisposition, CreateOptions,
3190
0
        ImpersonationLevel, SecurityFlags);
3191
0
  if (req == NULL) {
3192
0
    goto fail;
3193
0
  }
3194
3195
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3196
0
    goto fail;
3197
0
  }
3198
3199
0
  status = cli_ntcreate_recv(req, pfid, cr);
3200
0
 fail:
3201
0
  TALLOC_FREE(frame);
3202
0
  return status;
3203
0
}
3204
3205
struct cli_nttrans_create_state {
3206
  uint16_t fnum;
3207
  struct smb_create_returns cr;
3208
};
3209
3210
static void cli_nttrans_create_done(struct tevent_req *subreq);
3211
3212
struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
3213
             struct tevent_context *ev,
3214
             struct cli_state *cli,
3215
             const char *fname,
3216
             uint32_t CreatFlags,
3217
             uint32_t DesiredAccess,
3218
             uint32_t FileAttributes,
3219
             uint32_t ShareAccess,
3220
             uint32_t CreateDisposition,
3221
             uint32_t CreateOptions,
3222
             uint8_t SecurityFlags,
3223
             struct security_descriptor *secdesc,
3224
             struct ea_struct *eas,
3225
             int num_eas)
3226
0
{
3227
0
  struct tevent_req *req, *subreq;
3228
0
  struct cli_nttrans_create_state *state;
3229
0
  uint8_t *param;
3230
0
  uint8_t *secdesc_buf;
3231
0
  size_t secdesc_len;
3232
0
  NTSTATUS status;
3233
0
  size_t converted_len;
3234
0
  uint16_t additional_flags2 = 0;
3235
0
  char *fname_cp = NULL;
3236
3237
0
  req = tevent_req_create(mem_ctx,
3238
0
        &state, struct cli_nttrans_create_state);
3239
0
  if (req == NULL) {
3240
0
    return NULL;
3241
0
  }
3242
3243
0
  if (secdesc != NULL) {
3244
0
    status = marshall_sec_desc(talloc_tos(), secdesc,
3245
0
             &secdesc_buf, &secdesc_len);
3246
0
    if (tevent_req_nterror(req, status)) {
3247
0
      DEBUG(10, ("marshall_sec_desc failed: %s\n",
3248
0
           nt_errstr(status)));
3249
0
      return tevent_req_post(req, ev);
3250
0
    }
3251
0
  } else {
3252
0
    secdesc_buf = NULL;
3253
0
    secdesc_len = 0;
3254
0
  }
3255
3256
0
  if (num_eas != 0) {
3257
    /*
3258
     * TODO ;-)
3259
     */
3260
0
    tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
3261
0
    return tevent_req_post(req, ev);
3262
0
  }
3263
3264
0
  param = talloc_array(state, uint8_t, 53);
3265
0
  if (tevent_req_nomem(param, req)) {
3266
0
    return tevent_req_post(req, ev);
3267
0
  }
3268
3269
  /*
3270
   * SMBntcreateX on a DFS share must use DFS names.
3271
   */
3272
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
3273
0
  if (tevent_req_nomem(fname_cp, req)) {
3274
0
    return tevent_req_post(req, ev);
3275
0
  }
3276
0
  param = trans2_bytes_push_str(param,
3277
0
              smbXcli_conn_use_unicode(cli->conn),
3278
0
              fname_cp,
3279
0
              strlen(fname_cp),
3280
0
              &converted_len);
3281
0
  if (tevent_req_nomem(param, req)) {
3282
0
    return tevent_req_post(req, ev);
3283
0
  }
3284
3285
0
  if (clistr_is_previous_version_path(fname)) {
3286
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
3287
0
  }
3288
3289
0
  SIVAL(param, 0, CreatFlags);
3290
0
  SIVAL(param, 4, 0x0);  /* RootDirectoryFid */
3291
0
  SIVAL(param, 8, DesiredAccess);
3292
0
  SIVAL(param, 12, 0x0); /* AllocationSize */
3293
0
  SIVAL(param, 16, 0x0); /* AllocationSize */
3294
0
  SIVAL(param, 20, FileAttributes);
3295
0
  SIVAL(param, 24, ShareAccess);
3296
0
  SIVAL(param, 28, CreateDisposition);
3297
0
  SIVAL(param, 32, CreateOptions |
3298
0
    (cli->backup_intent ? FILE_OPEN_FOR_BACKUP_INTENT : 0));
3299
0
  SIVAL(param, 36, secdesc_len);
3300
0
  SIVAL(param, 40, 0);  /* EA length*/
3301
0
  SIVAL(param, 44, converted_len);
3302
0
  SIVAL(param, 48, 0x02); /* ImpersonationLevel */
3303
0
  SCVAL(param, 52, SecurityFlags);
3304
3305
0
  subreq = cli_trans_send(state, ev, cli,
3306
0
        additional_flags2, /* additional_flags2 */
3307
0
        SMBnttrans,
3308
0
        NULL, -1, /* name, fid */
3309
0
        NT_TRANSACT_CREATE, 0,
3310
0
        NULL, 0, 0, /* setup */
3311
0
        param, talloc_get_size(param), 128, /* param */
3312
0
        secdesc_buf, secdesc_len, 0); /* data */
3313
0
  if (tevent_req_nomem(subreq, req)) {
3314
0
    return tevent_req_post(req, ev);
3315
0
  }
3316
0
  tevent_req_set_callback(subreq, cli_nttrans_create_done, req);
3317
0
  return req;
3318
0
}
3319
3320
static void cli_nttrans_create_done(struct tevent_req *subreq)
3321
0
{
3322
0
  struct tevent_req *req = tevent_req_callback_data(
3323
0
    subreq, struct tevent_req);
3324
0
  struct cli_nttrans_create_state *state = tevent_req_data(
3325
0
    req, struct cli_nttrans_create_state);
3326
0
  uint8_t *param;
3327
0
  uint32_t num_param;
3328
0
  NTSTATUS status;
3329
3330
0
  status = cli_trans_recv(subreq, talloc_tos(), NULL,
3331
0
        NULL, 0, NULL, /* rsetup */
3332
0
        &param, 69, &num_param,
3333
0
        NULL, 0, NULL);
3334
0
  if (tevent_req_nterror(req, status)) {
3335
0
    return;
3336
0
  }
3337
0
  state->cr.oplock_level = CVAL(param, 0);
3338
0
  state->fnum = SVAL(param, 2);
3339
0
  state->cr.create_action = IVAL(param, 4);
3340
0
  state->cr.creation_time = BVAL(param, 12);
3341
0
  state->cr.last_access_time = BVAL(param, 20);
3342
0
  state->cr.last_write_time = BVAL(param, 28);
3343
0
  state->cr.change_time   = BVAL(param, 36);
3344
0
  state->cr.file_attributes = IVAL(param, 44);
3345
0
  state->cr.allocation_size = BVAL(param, 48);
3346
0
  state->cr.end_of_file   = BVAL(param, 56);
3347
3348
0
  TALLOC_FREE(param);
3349
0
  tevent_req_done(req);
3350
0
}
3351
3352
NTSTATUS cli_nttrans_create_recv(struct tevent_req *req,
3353
      uint16_t *fnum,
3354
      struct smb_create_returns *cr)
3355
0
{
3356
0
  struct cli_nttrans_create_state *state = tevent_req_data(
3357
0
    req, struct cli_nttrans_create_state);
3358
0
  NTSTATUS status;
3359
3360
0
  if (tevent_req_is_nterror(req, &status)) {
3361
0
    return status;
3362
0
  }
3363
0
  *fnum = state->fnum;
3364
0
  if (cr != NULL) {
3365
0
    *cr = state->cr;
3366
0
  }
3367
0
  return NT_STATUS_OK;
3368
0
}
3369
3370
NTSTATUS cli_nttrans_create(struct cli_state *cli,
3371
          const char *fname,
3372
          uint32_t CreatFlags,
3373
          uint32_t DesiredAccess,
3374
          uint32_t FileAttributes,
3375
          uint32_t ShareAccess,
3376
          uint32_t CreateDisposition,
3377
          uint32_t CreateOptions,
3378
          uint8_t SecurityFlags,
3379
          struct security_descriptor *secdesc,
3380
          struct ea_struct *eas,
3381
          int num_eas,
3382
          uint16_t *pfid,
3383
          struct smb_create_returns *cr)
3384
0
{
3385
0
  TALLOC_CTX *frame = talloc_stackframe();
3386
0
  struct tevent_context *ev;
3387
0
  struct tevent_req *req;
3388
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
3389
3390
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
3391
    /*
3392
     * Can't use sync call while an async call is in flight
3393
     */
3394
0
    status = NT_STATUS_INVALID_PARAMETER;
3395
0
    goto fail;
3396
0
  }
3397
0
  ev = samba_tevent_context_init(frame);
3398
0
  if (ev == NULL) {
3399
0
    goto fail;
3400
0
  }
3401
0
  req = cli_nttrans_create_send(frame, ev, cli, fname, CreatFlags,
3402
0
              DesiredAccess, FileAttributes,
3403
0
              ShareAccess, CreateDisposition,
3404
0
              CreateOptions, SecurityFlags,
3405
0
              secdesc, eas, num_eas);
3406
0
  if (req == NULL) {
3407
0
    goto fail;
3408
0
  }
3409
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3410
0
    goto fail;
3411
0
  }
3412
0
  status = cli_nttrans_create_recv(req, pfid, cr);
3413
0
 fail:
3414
0
  TALLOC_FREE(frame);
3415
0
  return status;
3416
0
}
3417
3418
/****************************************************************************
3419
 Open a file
3420
 WARNING: if you open with O_WRONLY then getattrE won't work!
3421
****************************************************************************/
3422
3423
struct cli_openx_state {
3424
  const char *fname;
3425
  uint16_t vwv[15];
3426
  uint16_t fnum;
3427
  struct iovec bytes;
3428
};
3429
3430
static void cli_openx_done(struct tevent_req *subreq);
3431
3432
struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
3433
           struct tevent_context *ev,
3434
           struct cli_state *cli, const char *fname,
3435
           int flags, int share_mode,
3436
           struct tevent_req **psmbreq)
3437
0
{
3438
0
  struct tevent_req *req, *subreq;
3439
0
  struct cli_openx_state *state;
3440
0
  unsigned openfn;
3441
0
  unsigned accessmode;
3442
0
  uint8_t additional_flags;
3443
0
  uint16_t additional_flags2 = 0;
3444
0
  uint8_t *bytes;
3445
0
  char *fname_cp = NULL;
3446
3447
0
  req = tevent_req_create(mem_ctx, &state, struct cli_openx_state);
3448
0
  if (req == NULL) {
3449
0
    return NULL;
3450
0
  }
3451
3452
0
  openfn = 0;
3453
0
  if (flags & O_CREAT) {
3454
0
    openfn |= (1<<4);
3455
0
  }
3456
0
  if (!(flags & O_EXCL)) {
3457
0
    if (flags & O_TRUNC)
3458
0
      openfn |= (1<<1);
3459
0
    else
3460
0
      openfn |= (1<<0);
3461
0
  }
3462
3463
0
  accessmode = (share_mode<<4);
3464
3465
0
  if ((flags & O_ACCMODE) == O_RDWR) {
3466
0
    accessmode |= 2;
3467
0
  } else if ((flags & O_ACCMODE) == O_WRONLY) {
3468
0
    accessmode |= 1;
3469
0
  }
3470
3471
0
#if defined(O_SYNC)
3472
0
  if ((flags & O_SYNC) == O_SYNC) {
3473
0
    accessmode |= (1<<14);
3474
0
  }
3475
0
#endif /* O_SYNC */
3476
3477
0
  if (share_mode == DENY_FCB) {
3478
0
    accessmode = 0xFF;
3479
0
  }
3480
3481
0
  SCVAL(state->vwv + 0, 0, 0xFF);
3482
0
  SCVAL(state->vwv + 0, 1, 0);
3483
0
  SSVAL(state->vwv + 1, 0, 0);
3484
0
  SSVAL(state->vwv + 2, 0, 0);  /* no additional info */
3485
0
  SSVAL(state->vwv + 3, 0, accessmode);
3486
0
  SSVAL(state->vwv + 4, 0, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
3487
0
  SSVAL(state->vwv + 5, 0, 0);
3488
0
  SIVAL(state->vwv + 6, 0, 0);
3489
0
  SSVAL(state->vwv + 8, 0, openfn);
3490
0
  SIVAL(state->vwv + 9, 0, 0);
3491
0
  SIVAL(state->vwv + 11, 0, 0);
3492
0
  SIVAL(state->vwv + 13, 0, 0);
3493
3494
0
  additional_flags = 0;
3495
3496
0
  if (cli->use_oplocks) {
3497
    /* if using oplocks then ask for a batch oplock via
3498
                   core and extended methods */
3499
0
    additional_flags =
3500
0
      FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
3501
0
    SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6);
3502
0
  }
3503
3504
0
  bytes = talloc_array(state, uint8_t, 0);
3505
0
  if (tevent_req_nomem(bytes, req)) {
3506
0
    return tevent_req_post(req, ev);
3507
0
  }
3508
  /*
3509
   * SMBopenX on a DFS share must use DFS names.
3510
   */
3511
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
3512
0
  if (tevent_req_nomem(fname_cp, req)) {
3513
0
    return tevent_req_post(req, ev);
3514
0
  }
3515
0
  bytes = smb_bytes_push_str(bytes,
3516
0
           smbXcli_conn_use_unicode(cli->conn),
3517
0
           fname_cp,
3518
0
           strlen(fname_cp)+1,
3519
0
           NULL);
3520
3521
0
  if (tevent_req_nomem(bytes, req)) {
3522
0
    return tevent_req_post(req, ev);
3523
0
  }
3524
3525
0
  if (clistr_is_previous_version_path(fname)) {
3526
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
3527
0
  }
3528
3529
0
  state->bytes.iov_base = (void *)bytes;
3530
0
  state->bytes.iov_len = talloc_get_size(bytes);
3531
3532
0
  subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags,
3533
0
      additional_flags2, 15, state->vwv, 1, &state->bytes);
3534
0
  if (subreq == NULL) {
3535
0
    TALLOC_FREE(req);
3536
0
    return NULL;
3537
0
  }
3538
0
  tevent_req_set_callback(subreq, cli_openx_done, req);
3539
0
  *psmbreq = subreq;
3540
0
  return req;
3541
0
}
3542
3543
struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3544
         struct cli_state *cli, const char *fname,
3545
         int flags, int share_mode)
3546
0
{
3547
0
  struct tevent_req *req, *subreq;
3548
0
  NTSTATUS status;
3549
3550
0
  req = cli_openx_create(mem_ctx, ev, cli, fname, flags, share_mode,
3551
0
            &subreq);
3552
0
  if (req == NULL) {
3553
0
    return NULL;
3554
0
  }
3555
3556
0
  status = smb1cli_req_chain_submit(&subreq, 1);
3557
0
  if (tevent_req_nterror(req, status)) {
3558
0
    return tevent_req_post(req, ev);
3559
0
  }
3560
0
  return req;
3561
0
}
3562
3563
static void cli_openx_done(struct tevent_req *subreq)
3564
0
{
3565
0
  struct tevent_req *req = tevent_req_callback_data(
3566
0
    subreq, struct tevent_req);
3567
0
  struct cli_openx_state *state = tevent_req_data(
3568
0
    req, struct cli_openx_state);
3569
0
  uint8_t wct;
3570
0
  uint16_t *vwv;
3571
0
  NTSTATUS status;
3572
3573
0
  status = cli_smb_recv(subreq, state, NULL, 3, &wct, &vwv, NULL,
3574
0
            NULL);
3575
0
  TALLOC_FREE(subreq);
3576
0
  if (tevent_req_nterror(req, status)) {
3577
0
    return;
3578
0
  }
3579
0
  state->fnum = SVAL(vwv+2, 0);
3580
0
  tevent_req_done(req);
3581
0
}
3582
3583
NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *pfnum)
3584
0
{
3585
0
  struct cli_openx_state *state = tevent_req_data(
3586
0
    req, struct cli_openx_state);
3587
0
  NTSTATUS status;
3588
3589
0
  if (tevent_req_is_nterror(req, &status)) {
3590
0
    return status;
3591
0
  }
3592
0
  *pfnum = state->fnum;
3593
0
  return NT_STATUS_OK;
3594
0
}
3595
3596
NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags,
3597
       int share_mode, uint16_t *pfnum)
3598
0
{
3599
0
  TALLOC_CTX *frame = talloc_stackframe();
3600
0
  struct tevent_context *ev;
3601
0
  struct tevent_req *req;
3602
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
3603
3604
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
3605
    /*
3606
     * Can't use sync call while an async call is in flight
3607
     */
3608
0
    status = NT_STATUS_INVALID_PARAMETER;
3609
0
    goto fail;
3610
0
  }
3611
3612
0
  ev = samba_tevent_context_init(frame);
3613
0
  if (ev == NULL) {
3614
0
    goto fail;
3615
0
  }
3616
3617
0
  req = cli_openx_send(frame, ev, cli, fname, flags, share_mode);
3618
0
  if (req == NULL) {
3619
0
    goto fail;
3620
0
  }
3621
3622
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3623
0
    goto fail;
3624
0
  }
3625
3626
0
  status = cli_openx_recv(req, pfnum);
3627
0
 fail:
3628
0
  TALLOC_FREE(frame);
3629
0
  return status;
3630
0
}
3631
/****************************************************************************
3632
 Synchronous wrapper function that does an NtCreateX open by preference
3633
 and falls back to openX if this fails.
3634
****************************************************************************/
3635
3636
NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
3637
      int share_mode_in, uint16_t *pfnum)
3638
0
{
3639
0
  NTSTATUS status;
3640
0
  unsigned int openfn = 0;
3641
0
  unsigned int dos_deny = 0;
3642
0
  uint32_t access_mask, share_mode, create_disposition, create_options;
3643
0
  struct smb_create_returns cr = {0};
3644
3645
  /* Do the initial mapping into OpenX parameters. */
3646
0
  if (flags & O_CREAT) {
3647
0
    openfn |= (1<<4);
3648
0
  }
3649
0
  if (!(flags & O_EXCL)) {
3650
0
    if (flags & O_TRUNC)
3651
0
      openfn |= (1<<1);
3652
0
    else
3653
0
      openfn |= (1<<0);
3654
0
  }
3655
3656
0
  dos_deny = (share_mode_in<<4);
3657
3658
0
  if ((flags & O_ACCMODE) == O_RDWR) {
3659
0
    dos_deny |= 2;
3660
0
  } else if ((flags & O_ACCMODE) == O_WRONLY) {
3661
0
    dos_deny |= 1;
3662
0
  }
3663
3664
0
#if defined(O_SYNC)
3665
0
  if (flags & O_SYNC) {
3666
0
    dos_deny |= (1<<14);
3667
0
  }
3668
0
#endif /* O_SYNC */
3669
3670
0
  if (share_mode_in == DENY_FCB) {
3671
0
    dos_deny = 0xFF;
3672
0
  }
3673
3674
0
  if (!map_open_params_to_ntcreate(fname, dos_deny,
3675
0
          openfn, &access_mask,
3676
0
          &share_mode, &create_disposition,
3677
0
          &create_options, NULL)) {
3678
0
    goto try_openx;
3679
0
  }
3680
3681
0
  status = cli_ntcreate(cli,
3682
0
        fname,
3683
0
        0,
3684
0
        access_mask,
3685
0
        0,
3686
0
        share_mode,
3687
0
        create_disposition,
3688
0
        create_options,
3689
0
        0,
3690
0
        pfnum,
3691
0
        &cr);
3692
3693
  /* Try and cope will all variants of "we don't do this call"
3694
     and fall back to openX. */
3695
3696
0
  if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
3697
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
3698
0
      NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
3699
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
3700
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
3701
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
3702
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
3703
0
      NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
3704
0
      NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
3705
0
    goto try_openx;
3706
0
  }
3707
3708
0
  if (NT_STATUS_IS_OK(status) &&
3709
0
      (create_options & FILE_NON_DIRECTORY_FILE) &&
3710
0
      (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
3711
0
  {
3712
    /*
3713
     * Some (broken) servers return a valid handle
3714
     * for directories even if FILE_NON_DIRECTORY_FILE
3715
     * is set. Just close the handle and set the
3716
     * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
3717
     */
3718
0
    status = cli_close(cli, *pfnum);
3719
0
    if (!NT_STATUS_IS_OK(status)) {
3720
0
      return status;
3721
0
    }
3722
0
    status = NT_STATUS_FILE_IS_A_DIRECTORY;
3723
0
  }
3724
3725
0
  return status;
3726
3727
0
  try_openx:
3728
3729
0
  return cli_openx(cli, fname, flags, share_mode_in, pfnum);
3730
0
}
3731
3732
/****************************************************************************
3733
 Close a file.
3734
****************************************************************************/
3735
3736
struct cli_smb1_close_state {
3737
  uint16_t vwv[3];
3738
};
3739
3740
static void cli_smb1_close_done(struct tevent_req *subreq);
3741
3742
struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
3743
        struct tevent_context *ev,
3744
        struct cli_state *cli,
3745
        uint16_t fnum,
3746
        struct tevent_req **psubreq)
3747
0
{
3748
0
  struct tevent_req *req, *subreq;
3749
0
  struct cli_smb1_close_state *state;
3750
3751
0
  req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
3752
0
  if (req == NULL) {
3753
0
    return NULL;
3754
0
  }
3755
3756
0
  SSVAL(state->vwv+0, 0, fnum);
3757
0
  SIVALS(state->vwv+1, 0, -1);
3758
3759
0
  subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 0,
3760
0
        3, state->vwv, 0, NULL);
3761
0
  if (subreq == NULL) {
3762
0
    TALLOC_FREE(req);
3763
0
    return NULL;
3764
0
  }
3765
0
  tevent_req_set_callback(subreq, cli_smb1_close_done, req);
3766
0
  *psubreq = subreq;
3767
0
  return req;
3768
0
}
3769
3770
static void cli_smb1_close_done(struct tevent_req *subreq)
3771
0
{
3772
0
  struct tevent_req *req = tevent_req_callback_data(
3773
0
    subreq, struct tevent_req);
3774
0
  NTSTATUS status;
3775
3776
0
  status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
3777
0
  TALLOC_FREE(subreq);
3778
0
  if (tevent_req_nterror(req, status)) {
3779
0
    return;
3780
0
  }
3781
0
  tevent_req_done(req);
3782
0
}
3783
3784
struct cli_close_state {
3785
  int dummy;
3786
};
3787
3788
static void cli_close_done(struct tevent_req *subreq);
3789
3790
struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
3791
          struct tevent_context *ev,
3792
          struct cli_state *cli,
3793
          uint16_t fnum,
3794
          uint16_t flags)
3795
0
{
3796
0
  struct tevent_req *req, *subreq;
3797
0
  struct cli_close_state *state;
3798
0
  NTSTATUS status;
3799
3800
0
  req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
3801
0
  if (req == NULL) {
3802
0
    return NULL;
3803
0
  }
3804
3805
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3806
0
    subreq = cli_smb2_close_fnum_send(state, ev, cli, fnum, flags);
3807
0
    if (tevent_req_nomem(subreq, req)) {
3808
0
      return tevent_req_post(req, ev);
3809
0
    }
3810
0
  } else {
3811
0
    struct tevent_req *ch_req = NULL;
3812
0
    subreq = cli_smb1_close_create(state, ev, cli, fnum, &ch_req);
3813
0
    if (tevent_req_nomem(subreq, req)) {
3814
0
      return tevent_req_post(req, ev);
3815
0
    }
3816
0
    status = smb1cli_req_chain_submit(&ch_req, 1);
3817
0
    if (tevent_req_nterror(req, status)) {
3818
0
      return tevent_req_post(req, ev);
3819
0
    }
3820
0
  }
3821
3822
0
  tevent_req_set_callback(subreq, cli_close_done, req);
3823
0
  return req;
3824
0
}
3825
3826
static void cli_close_done(struct tevent_req *subreq)
3827
0
{
3828
0
  struct tevent_req *req = tevent_req_callback_data(
3829
0
    subreq, struct tevent_req);
3830
0
  NTSTATUS status = NT_STATUS_OK;
3831
0
  bool err = tevent_req_is_nterror(subreq, &status);
3832
3833
0
  TALLOC_FREE(subreq);
3834
0
  if (err) {
3835
0
    tevent_req_nterror(req, status);
3836
0
    return;
3837
0
  }
3838
0
  tevent_req_done(req);
3839
0
}
3840
3841
NTSTATUS cli_close_recv(struct tevent_req *req)
3842
0
{
3843
0
  return tevent_req_simple_recv_ntstatus(req);
3844
0
}
3845
3846
NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
3847
0
{
3848
0
  TALLOC_CTX *frame = NULL;
3849
0
  struct tevent_context *ev;
3850
0
  struct tevent_req *req;
3851
0
  NTSTATUS status = NT_STATUS_OK;
3852
3853
0
  frame = talloc_stackframe();
3854
3855
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
3856
    /*
3857
     * Can't use sync call while an async call is in flight
3858
     */
3859
0
    status = NT_STATUS_INVALID_PARAMETER;
3860
0
    goto fail;
3861
0
  }
3862
3863
0
  ev = samba_tevent_context_init(frame);
3864
0
  if (ev == NULL) {
3865
0
    status = NT_STATUS_NO_MEMORY;
3866
0
    goto fail;
3867
0
  }
3868
3869
0
  req = cli_close_send(frame, ev, cli, fnum, 0);
3870
0
  if (req == NULL) {
3871
0
    status = NT_STATUS_NO_MEMORY;
3872
0
    goto fail;
3873
0
  }
3874
3875
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3876
0
    goto fail;
3877
0
  }
3878
3879
0
  status = cli_close_recv(req);
3880
0
 fail:
3881
0
  TALLOC_FREE(frame);
3882
0
  return status;
3883
0
}
3884
3885
/****************************************************************************
3886
 Truncate a file to a specified size
3887
****************************************************************************/
3888
3889
struct ftrunc_state {
3890
  uint8_t data[8];
3891
};
3892
3893
static void cli_ftruncate_done(struct tevent_req *subreq)
3894
0
{
3895
0
  NTSTATUS status = cli_setfileinfo_recv(subreq);
3896
0
  tevent_req_simple_finish_ntstatus(subreq, status);
3897
0
}
3898
3899
struct tevent_req *cli_ftruncate_send(TALLOC_CTX *mem_ctx,
3900
          struct tevent_context *ev,
3901
          struct cli_state *cli,
3902
          uint16_t fnum,
3903
          uint64_t size)
3904
0
{
3905
0
  struct tevent_req *req = NULL, *subreq = NULL;
3906
0
  struct ftrunc_state *state = NULL;
3907
3908
0
  req = tevent_req_create(mem_ctx, &state, struct ftrunc_state);
3909
0
  if (req == NULL) {
3910
0
    return NULL;
3911
0
  }
3912
3913
  /* Setup data array. */
3914
0
        SBVAL(state->data, 0, size);
3915
3916
0
  subreq = cli_setfileinfo_send(
3917
0
    state,
3918
0
    ev,
3919
0
    cli,
3920
0
    fnum,
3921
0
    SMB_SET_FILE_END_OF_FILE_INFO,
3922
0
    state->data,
3923
0
    sizeof(state->data));
3924
3925
0
  if (tevent_req_nomem(subreq, req)) {
3926
0
    return tevent_req_post(req, ev);
3927
0
  }
3928
0
  tevent_req_set_callback(subreq, cli_ftruncate_done, req);
3929
0
  return req;
3930
0
}
3931
3932
NTSTATUS cli_ftruncate_recv(struct tevent_req *req)
3933
0
{
3934
0
  return tevent_req_simple_recv_ntstatus(req);
3935
0
}
3936
3937
NTSTATUS cli_ftruncate(struct cli_state *cli, uint16_t fnum, uint64_t size)
3938
0
{
3939
0
  TALLOC_CTX *frame = NULL;
3940
0
  struct tevent_context *ev = NULL;
3941
0
  struct tevent_req *req = NULL;
3942
0
  NTSTATUS status = NT_STATUS_OK;
3943
3944
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3945
0
    return cli_smb2_ftruncate(cli, fnum, size);
3946
0
  }
3947
3948
0
  frame = talloc_stackframe();
3949
3950
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
3951
    /*
3952
     * Can't use sync call while an async call is in flight
3953
     */
3954
0
    status = NT_STATUS_INVALID_PARAMETER;
3955
0
    goto fail;
3956
0
  }
3957
3958
0
  ev = samba_tevent_context_init(frame);
3959
0
  if (ev == NULL) {
3960
0
    status = NT_STATUS_NO_MEMORY;
3961
0
    goto fail;
3962
0
  }
3963
3964
0
  req = cli_ftruncate_send(frame,
3965
0
        ev,
3966
0
        cli,
3967
0
        fnum,
3968
0
        size);
3969
0
  if (req == NULL) {
3970
0
    status = NT_STATUS_NO_MEMORY;
3971
0
    goto fail;
3972
0
  }
3973
3974
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3975
0
    goto fail;
3976
0
  }
3977
3978
0
  status = cli_ftruncate_recv(req);
3979
3980
0
 fail:
3981
0
  TALLOC_FREE(frame);
3982
0
  return status;
3983
0
}
3984
3985
static uint8_t *cli_lockingx_put_locks(
3986
  uint8_t *buf,
3987
  bool large,
3988
  uint16_t num_locks,
3989
  const struct smb1_lock_element *locks)
3990
0
{
3991
0
  uint16_t i;
3992
3993
0
  for (i=0; i<num_locks; i++) {
3994
0
    const struct smb1_lock_element *e = &locks[i];
3995
0
    if (large) {
3996
0
      SSVAL(buf, 0, e->pid);
3997
0
      SSVAL(buf, 2, 0);
3998
0
      SOFF_T_R(buf, 4, e->offset);
3999
0
      SOFF_T_R(buf, 12, e->length);
4000
0
      buf += 20;
4001
0
    } else {
4002
0
      SSVAL(buf, 0, e->pid);
4003
0
      SIVAL(buf, 2, e->offset);
4004
0
      SIVAL(buf, 6, e->length);
4005
0
      buf += 10;
4006
0
    }
4007
0
  }
4008
0
  return buf;
4009
0
}
4010
4011
struct cli_lockingx_state {
4012
  uint16_t vwv[8];
4013
  struct iovec bytes;
4014
  struct tevent_req *subreq;
4015
};
4016
4017
static void cli_lockingx_done(struct tevent_req *subreq);
4018
static bool cli_lockingx_cancel(struct tevent_req *req);
4019
4020
struct tevent_req *cli_lockingx_create(
4021
  TALLOC_CTX *mem_ctx,
4022
  struct tevent_context *ev,
4023
  struct cli_state *cli,
4024
  uint16_t fnum,
4025
  uint8_t typeoflock,
4026
  uint8_t newoplocklevel,
4027
  int32_t timeout,
4028
  uint16_t num_unlocks,
4029
  const struct smb1_lock_element *unlocks,
4030
  uint16_t num_locks,
4031
  const struct smb1_lock_element *locks,
4032
  struct tevent_req **psmbreq)
4033
0
{
4034
0
  struct tevent_req *req = NULL, *subreq = NULL;
4035
0
  struct cli_lockingx_state *state = NULL;
4036
0
  uint16_t *vwv;
4037
0
  uint8_t *p;
4038
0
  const bool large = (typeoflock & LOCKING_ANDX_LARGE_FILES);
4039
0
  const size_t element_len = large ? 20 : 10;
4040
4041
  /* uint16->size_t, no overflow */
4042
0
  const size_t num_elements = (size_t)num_locks + (size_t)num_unlocks;
4043
4044
  /* at most 20*2*65535 = 2621400, no overflow */
4045
0
  const size_t num_bytes = num_elements * element_len;
4046
4047
0
  req = tevent_req_create(mem_ctx, &state, struct cli_lockingx_state);
4048
0
  if (req == NULL) {
4049
0
    return NULL;
4050
0
  }
4051
0
  vwv = state->vwv;
4052
4053
0
  SCVAL(vwv + 0, 0, 0xFF);
4054
0
  SCVAL(vwv + 0, 1, 0);
4055
0
  SSVAL(vwv + 1, 0, 0);
4056
0
  SSVAL(vwv + 2, 0, fnum);
4057
0
  SCVAL(vwv + 3, 0, typeoflock);
4058
0
  SCVAL(vwv + 3, 1, newoplocklevel);
4059
0
  SIVALS(vwv + 4, 0, timeout);
4060
0
  SSVAL(vwv + 6, 0, num_unlocks);
4061
0
  SSVAL(vwv + 7, 0, num_locks);
4062
4063
0
  state->bytes.iov_len = num_bytes;
4064
0
  state->bytes.iov_base = talloc_array(state, uint8_t, num_bytes);
4065
0
  if (tevent_req_nomem(state->bytes.iov_base, req)) {
4066
0
    return tevent_req_post(req, ev);
4067
0
  }
4068
4069
0
  p = cli_lockingx_put_locks(
4070
0
    state->bytes.iov_base, large, num_unlocks, unlocks);
4071
0
  cli_lockingx_put_locks(p, large, num_locks, locks);
4072
4073
0
  subreq = cli_smb_req_create(
4074
0
    state, ev, cli, SMBlockingX, 0, 0, 8, vwv, 1, &state->bytes);
4075
0
  if (tevent_req_nomem(subreq, req)) {
4076
0
    return tevent_req_post(req, ev);
4077
0
  }
4078
0
  tevent_req_set_callback(subreq, cli_lockingx_done, req);
4079
0
  *psmbreq = subreq;
4080
0
  return req;
4081
0
}
4082
4083
struct tevent_req *cli_lockingx_send(
4084
  TALLOC_CTX *mem_ctx,
4085
  struct tevent_context *ev,
4086
  struct cli_state *cli,
4087
  uint16_t fnum,
4088
  uint8_t typeoflock,
4089
  uint8_t newoplocklevel,
4090
  int32_t timeout,
4091
  uint16_t num_unlocks,
4092
  const struct smb1_lock_element *unlocks,
4093
  uint16_t num_locks,
4094
  const struct smb1_lock_element *locks)
4095
0
{
4096
0
  struct tevent_req *req = NULL, *subreq = NULL;
4097
0
  struct cli_lockingx_state *state = NULL;
4098
0
  NTSTATUS status;
4099
4100
0
  req = cli_lockingx_create(
4101
0
    mem_ctx,
4102
0
    ev,
4103
0
    cli,
4104
0
    fnum,
4105
0
    typeoflock,
4106
0
    newoplocklevel,
4107
0
    timeout,
4108
0
    num_unlocks,
4109
0
    unlocks,
4110
0
    num_locks,
4111
0
    locks,
4112
0
    &subreq);
4113
0
  if (req == NULL) {
4114
0
    return NULL;
4115
0
  }
4116
0
  state = tevent_req_data(req, struct cli_lockingx_state);
4117
0
  state->subreq = subreq;
4118
4119
0
  status = smb1cli_req_chain_submit(&subreq, 1);
4120
0
  if (tevent_req_nterror(req, status)) {
4121
0
    return tevent_req_post(req, ev);
4122
0
  }
4123
0
  tevent_req_set_cancel_fn(req, cli_lockingx_cancel);
4124
0
  return req;
4125
0
}
4126
4127
static void cli_lockingx_done(struct tevent_req *subreq)
4128
0
{
4129
0
  NTSTATUS status = cli_smb_recv(
4130
0
    subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4131
0
  tevent_req_simple_finish_ntstatus(subreq, status);
4132
0
}
4133
4134
static bool cli_lockingx_cancel(struct tevent_req *req)
4135
0
{
4136
0
  struct cli_lockingx_state *state = tevent_req_data(
4137
0
    req, struct cli_lockingx_state);
4138
0
  if (state->subreq == NULL) {
4139
0
    return false;
4140
0
  }
4141
0
  return tevent_req_cancel(state->subreq);
4142
0
}
4143
4144
NTSTATUS cli_lockingx_recv(struct tevent_req *req)
4145
0
{
4146
0
  return tevent_req_simple_recv_ntstatus(req);
4147
0
}
4148
4149
NTSTATUS cli_lockingx(
4150
  struct cli_state *cli,
4151
  uint16_t fnum,
4152
  uint8_t typeoflock,
4153
  uint8_t newoplocklevel,
4154
  int32_t timeout,
4155
  uint16_t num_unlocks,
4156
  const struct smb1_lock_element *unlocks,
4157
  uint16_t num_locks,
4158
  const struct smb1_lock_element *locks)
4159
0
{
4160
0
  TALLOC_CTX *frame = talloc_stackframe();
4161
0
  struct tevent_context *ev = NULL;
4162
0
  struct tevent_req *req = NULL;
4163
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
4164
0
  unsigned int set_timeout = 0;
4165
0
  unsigned int saved_timeout = 0;
4166
4167
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
4168
0
    return NT_STATUS_INVALID_PARAMETER;
4169
0
  }
4170
0
  ev = samba_tevent_context_init(frame);
4171
0
  if (ev == NULL) {
4172
0
    goto fail;
4173
0
  }
4174
4175
0
  if (timeout != 0) {
4176
0
    if (timeout == -1) {
4177
0
      set_timeout = 0x7FFFFFFF;
4178
0
    } else {
4179
0
      set_timeout = timeout + 2*1000;
4180
0
    }
4181
0
    saved_timeout = cli_set_timeout(cli, set_timeout);
4182
0
  }
4183
4184
0
  req = cli_lockingx_send(
4185
0
    frame,
4186
0
    ev,
4187
0
    cli,
4188
0
    fnum,
4189
0
    typeoflock,
4190
0
    newoplocklevel,
4191
0
    timeout,
4192
0
    num_unlocks,
4193
0
    unlocks,
4194
0
    num_locks,
4195
0
    locks);
4196
0
  if (req == NULL) {
4197
0
    goto fail;
4198
0
  }
4199
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4200
0
    goto fail;
4201
0
  }
4202
0
  status = cli_lockingx_recv(req);
4203
4204
0
  if (saved_timeout != 0) {
4205
0
    cli_set_timeout(cli, saved_timeout);
4206
0
  }
4207
0
fail:
4208
0
  TALLOC_FREE(frame);
4209
0
  return status;
4210
0
}
4211
4212
/****************************************************************************
4213
 send a lock with a specified locktype
4214
 this is used for testing LOCKING_ANDX_CANCEL_LOCK
4215
****************************************************************************/
4216
4217
NTSTATUS cli_locktype(struct cli_state *cli, uint16_t fnum,
4218
          uint32_t offset, uint32_t len,
4219
          int timeout, unsigned char locktype)
4220
0
{
4221
0
  struct smb1_lock_element lck = {
4222
0
    .pid = cli_getpid(cli),
4223
0
    .offset = offset,
4224
0
    .length = len,
4225
0
  };
4226
0
  NTSTATUS status;
4227
4228
0
  status = cli_lockingx(
4229
0
    cli,        /* cli */
4230
0
    fnum,       /* fnum */
4231
0
    locktype,     /* typeoflock */
4232
0
    0,        /* newoplocklevel */
4233
0
    timeout,      /* timeout */
4234
0
    0,        /* num_unlocks */
4235
0
    NULL,       /* unlocks */
4236
0
    1,        /* num_locks */
4237
0
    &lck);        /* locks */
4238
0
  return status;
4239
0
}
4240
4241
/****************************************************************************
4242
 Lock a file.
4243
 note that timeout is in units of 2 milliseconds
4244
****************************************************************************/
4245
4246
NTSTATUS cli_lock32(struct cli_state *cli, uint16_t fnum,
4247
      uint32_t offset, uint32_t len, int timeout,
4248
      enum brl_type lock_type)
4249
0
{
4250
0
  NTSTATUS status;
4251
4252
0
  status = cli_locktype(cli, fnum, offset, len, timeout,
4253
0
            (lock_type == READ_LOCK? 1 : 0));
4254
0
  return status;
4255
0
}
4256
4257
/****************************************************************************
4258
 Unlock a file.
4259
****************************************************************************/
4260
4261
struct cli_unlock_state {
4262
  struct smb1_lock_element lck;
4263
};
4264
4265
static void cli_unlock_done(struct tevent_req *subreq);
4266
4267
struct tevent_req *cli_unlock_send(TALLOC_CTX *mem_ctx,
4268
        struct tevent_context *ev,
4269
        struct cli_state *cli,
4270
        uint16_t fnum,
4271
        uint64_t offset,
4272
        uint64_t len)
4273
4274
0
{
4275
0
  struct tevent_req *req = NULL, *subreq = NULL;
4276
0
  struct cli_unlock_state *state = NULL;
4277
4278
0
  req = tevent_req_create(mem_ctx, &state, struct cli_unlock_state);
4279
0
  if (req == NULL) {
4280
0
    return NULL;
4281
0
  }
4282
0
  state->lck = (struct smb1_lock_element) {
4283
0
    .pid = cli_getpid(cli),
4284
0
    .offset = offset,
4285
0
    .length = len,
4286
0
  };
4287
4288
0
  subreq = cli_lockingx_send(
4289
0
    state,        /* mem_ctx */
4290
0
    ev,       /* tevent_context */
4291
0
    cli,        /* cli */
4292
0
    fnum,       /* fnum */
4293
0
    0,        /* typeoflock */
4294
0
    0,        /* newoplocklevel */
4295
0
    0,        /* timeout */
4296
0
    1,        /* num_unlocks */
4297
0
    &state->lck,      /* unlocks */
4298
0
    0,        /* num_locks */
4299
0
    NULL);        /* locks */
4300
0
  if (tevent_req_nomem(subreq, req)) {
4301
0
    return tevent_req_post(req, ev);
4302
0
  }
4303
0
  tevent_req_set_callback(subreq, cli_unlock_done, req);
4304
0
  return req;
4305
0
}
4306
4307
static void cli_unlock_done(struct tevent_req *subreq)
4308
0
{
4309
0
  NTSTATUS status = cli_lockingx_recv(subreq);
4310
0
  tevent_req_simple_finish_ntstatus(subreq, status);
4311
0
}
4312
4313
NTSTATUS cli_unlock_recv(struct tevent_req *req)
4314
0
{
4315
0
  return tevent_req_simple_recv_ntstatus(req);
4316
0
}
4317
4318
NTSTATUS cli_unlock(struct cli_state *cli,
4319
      uint16_t fnum,
4320
      uint32_t offset,
4321
      uint32_t len)
4322
0
{
4323
0
  TALLOC_CTX *frame = talloc_stackframe();
4324
0
  struct tevent_context *ev;
4325
0
  struct tevent_req *req;
4326
0
  NTSTATUS status = NT_STATUS_OK;
4327
4328
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
4329
    /*
4330
     * Can't use sync call while an async call is in flight
4331
     */
4332
0
    status = NT_STATUS_INVALID_PARAMETER;
4333
0
    goto fail;
4334
0
  }
4335
4336
0
  ev = samba_tevent_context_init(frame);
4337
0
  if (ev == NULL) {
4338
0
    status = NT_STATUS_NO_MEMORY;
4339
0
    goto fail;
4340
0
  }
4341
4342
0
  req = cli_unlock_send(frame, ev, cli,
4343
0
      fnum, offset, len);
4344
0
  if (req == NULL) {
4345
0
    status = NT_STATUS_NO_MEMORY;
4346
0
    goto fail;
4347
0
  }
4348
4349
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4350
0
    goto fail;
4351
0
  }
4352
4353
0
  status = cli_unlock_recv(req);
4354
4355
0
 fail:
4356
0
  TALLOC_FREE(frame);
4357
0
  return status;
4358
0
}
4359
4360
/****************************************************************************
4361
 Get/unlock a POSIX lock on a file - internal function.
4362
****************************************************************************/
4363
4364
struct posix_lock_state {
4365
        uint16_t setup;
4366
  uint8_t param[4];
4367
        uint8_t data[POSIX_LOCK_DATA_SIZE];
4368
};
4369
4370
static void cli_posix_unlock_internal_done(struct tevent_req *subreq)
4371
0
{
4372
0
  NTSTATUS status = cli_trans_recv(subreq, NULL, NULL, NULL, 0, NULL,
4373
0
           NULL, 0, NULL, NULL, 0, NULL);
4374
0
  tevent_req_simple_finish_ntstatus(subreq, status);
4375
0
}
4376
4377
static struct tevent_req *cli_posix_lock_internal_send(TALLOC_CTX *mem_ctx,
4378
          struct tevent_context *ev,
4379
          struct cli_state *cli,
4380
          uint16_t fnum,
4381
          uint64_t offset,
4382
          uint64_t len,
4383
          bool wait_lock,
4384
          enum brl_type lock_type)
4385
0
{
4386
0
  struct tevent_req *req = NULL, *subreq = NULL;
4387
0
  struct posix_lock_state *state = NULL;
4388
4389
0
  req = tevent_req_create(mem_ctx, &state, struct posix_lock_state);
4390
0
  if (req == NULL) {
4391
0
    return NULL;
4392
0
  }
4393
4394
  /* Setup setup word. */
4395
0
  SSVAL(&state->setup, 0, TRANSACT2_SETFILEINFO);
4396
4397
  /* Setup param array. */
4398
0
  SSVAL(&state->param, 0, fnum);
4399
0
  SSVAL(&state->param, 2, SMB_SET_POSIX_LOCK);
4400
4401
  /* Setup data array. */
4402
0
  switch (lock_type) {
4403
0
    case READ_LOCK:
4404
0
      SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4405
0
        POSIX_LOCK_TYPE_READ);
4406
0
      break;
4407
0
    case WRITE_LOCK:
4408
0
      SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4409
0
        POSIX_LOCK_TYPE_WRITE);
4410
0
      break;
4411
0
    case UNLOCK_LOCK:
4412
0
      SSVAL(&state->data, POSIX_LOCK_TYPE_OFFSET,
4413
0
        POSIX_LOCK_TYPE_UNLOCK);
4414
0
      break;
4415
0
    default:
4416
0
      return NULL;
4417
0
  }
4418
4419
0
  if (wait_lock) {
4420
0
    SSVAL(&state->data, POSIX_LOCK_FLAGS_OFFSET,
4421
0
        POSIX_LOCK_FLAG_WAIT);
4422
0
  } else {
4423
0
    SSVAL(state->data, POSIX_LOCK_FLAGS_OFFSET,
4424
0
        POSIX_LOCK_FLAG_NOWAIT);
4425
0
  }
4426
4427
0
  SIVAL(&state->data, POSIX_LOCK_PID_OFFSET, cli_getpid(cli));
4428
0
  SOFF_T(&state->data, POSIX_LOCK_START_OFFSET, offset);
4429
0
  SOFF_T(&state->data, POSIX_LOCK_LEN_OFFSET, len);
4430
4431
0
  subreq = cli_trans_send(state,                  /* mem ctx. */
4432
0
        ev,                     /* event ctx. */
4433
0
        cli,                    /* cli_state. */
4434
0
        0,      /* additional_flags2 */
4435
0
        SMBtrans2,              /* cmd. */
4436
0
        NULL,                   /* pipe name. */
4437
0
        -1,                     /* fid. */
4438
0
        0,                      /* function. */
4439
0
        0,                      /* flags. */
4440
0
        &state->setup,          /* setup. */
4441
0
        1,                      /* num setup uint16_t words. */
4442
0
        0,                      /* max returned setup. */
4443
0
        state->param,           /* param. */
4444
0
        4,      /* num param. */
4445
0
        2,                      /* max returned param. */
4446
0
        state->data,            /* data. */
4447
0
        POSIX_LOCK_DATA_SIZE,   /* num data. */
4448
0
        0);                     /* max returned data. */
4449
4450
0
  if (tevent_req_nomem(subreq, req)) {
4451
0
    return tevent_req_post(req, ev);
4452
0
  }
4453
0
  tevent_req_set_callback(subreq, cli_posix_unlock_internal_done, req);
4454
0
  return req;
4455
0
}
4456
4457
/****************************************************************************
4458
 POSIX Lock a file.
4459
****************************************************************************/
4460
4461
struct tevent_req *cli_posix_lock_send(TALLOC_CTX *mem_ctx,
4462
          struct tevent_context *ev,
4463
          struct cli_state *cli,
4464
          uint16_t fnum,
4465
          uint64_t offset,
4466
          uint64_t len,
4467
          bool wait_lock,
4468
          enum brl_type lock_type)
4469
0
{
4470
0
  return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4471
0
          wait_lock, lock_type);
4472
0
}
4473
4474
NTSTATUS cli_posix_lock_recv(struct tevent_req *req)
4475
0
{
4476
0
  return tevent_req_simple_recv_ntstatus(req);
4477
0
}
4478
4479
NTSTATUS cli_posix_lock(struct cli_state *cli, uint16_t fnum,
4480
      uint64_t offset, uint64_t len,
4481
      bool wait_lock, enum brl_type lock_type)
4482
0
{
4483
0
  TALLOC_CTX *frame = talloc_stackframe();
4484
0
  struct tevent_context *ev = NULL;
4485
0
  struct tevent_req *req = NULL;
4486
0
  NTSTATUS status = NT_STATUS_OK;
4487
4488
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
4489
    /*
4490
     * Can't use sync call while an async call is in flight
4491
     */
4492
0
    status = NT_STATUS_INVALID_PARAMETER;
4493
0
    goto fail;
4494
0
  }
4495
4496
0
  if (lock_type != READ_LOCK && lock_type != WRITE_LOCK) {
4497
0
    status = NT_STATUS_INVALID_PARAMETER;
4498
0
    goto fail;
4499
0
  }
4500
4501
0
  ev = samba_tevent_context_init(frame);
4502
0
  if (ev == NULL) {
4503
0
    status = NT_STATUS_NO_MEMORY;
4504
0
    goto fail;
4505
0
  }
4506
4507
0
  req = cli_posix_lock_send(frame,
4508
0
        ev,
4509
0
        cli,
4510
0
        fnum,
4511
0
        offset,
4512
0
        len,
4513
0
        wait_lock,
4514
0
        lock_type);
4515
0
  if (req == NULL) {
4516
0
    status = NT_STATUS_NO_MEMORY;
4517
0
    goto fail;
4518
0
  }
4519
4520
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4521
0
    goto fail;
4522
0
  }
4523
4524
0
  status = cli_posix_lock_recv(req);
4525
4526
0
 fail:
4527
0
  TALLOC_FREE(frame);
4528
0
  return status;
4529
0
}
4530
4531
/****************************************************************************
4532
 POSIX Unlock a file.
4533
****************************************************************************/
4534
4535
struct tevent_req *cli_posix_unlock_send(TALLOC_CTX *mem_ctx,
4536
          struct tevent_context *ev,
4537
          struct cli_state *cli,
4538
          uint16_t fnum,
4539
          uint64_t offset,
4540
          uint64_t len)
4541
0
{
4542
0
  return cli_posix_lock_internal_send(mem_ctx, ev, cli, fnum, offset, len,
4543
0
          false, UNLOCK_LOCK);
4544
0
}
4545
4546
NTSTATUS cli_posix_unlock_recv(struct tevent_req *req)
4547
0
{
4548
0
  return tevent_req_simple_recv_ntstatus(req);
4549
0
}
4550
4551
NTSTATUS cli_posix_unlock(struct cli_state *cli, uint16_t fnum, uint64_t offset, uint64_t len)
4552
0
{
4553
0
  TALLOC_CTX *frame = talloc_stackframe();
4554
0
  struct tevent_context *ev = NULL;
4555
0
  struct tevent_req *req = NULL;
4556
0
  NTSTATUS status = NT_STATUS_OK;
4557
4558
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
4559
    /*
4560
     * Can't use sync call while an async call is in flight
4561
     */
4562
0
    status = NT_STATUS_INVALID_PARAMETER;
4563
0
    goto fail;
4564
0
  }
4565
4566
0
  ev = samba_tevent_context_init(frame);
4567
0
  if (ev == NULL) {
4568
0
    status = NT_STATUS_NO_MEMORY;
4569
0
    goto fail;
4570
0
  }
4571
4572
0
  req = cli_posix_unlock_send(frame,
4573
0
        ev,
4574
0
        cli,
4575
0
        fnum,
4576
0
        offset,
4577
0
        len);
4578
0
  if (req == NULL) {
4579
0
    status = NT_STATUS_NO_MEMORY;
4580
0
    goto fail;
4581
0
  }
4582
4583
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4584
0
    goto fail;
4585
0
  }
4586
4587
0
  status = cli_posix_unlock_recv(req);
4588
4589
0
 fail:
4590
0
  TALLOC_FREE(frame);
4591
0
  return status;
4592
0
}
4593
4594
/****************************************************************************
4595
 Do a SMBgetattrE call.
4596
****************************************************************************/
4597
4598
static void cli_getattrE_done(struct tevent_req *subreq);
4599
4600
struct cli_getattrE_state {
4601
  uint16_t vwv[1];
4602
  int zone_offset;
4603
  uint32_t attr;
4604
  off_t size;
4605
  time_t change_time;
4606
  time_t access_time;
4607
  time_t write_time;
4608
};
4609
4610
struct tevent_req *cli_getattrE_send(TALLOC_CTX *mem_ctx,
4611
        struct tevent_context *ev,
4612
        struct cli_state *cli,
4613
        uint16_t fnum)
4614
0
{
4615
0
  struct tevent_req *req = NULL, *subreq = NULL;
4616
0
  struct cli_getattrE_state *state = NULL;
4617
0
  uint8_t additional_flags = 0;
4618
4619
0
  req = tevent_req_create(mem_ctx, &state, struct cli_getattrE_state);
4620
0
  if (req == NULL) {
4621
0
    return NULL;
4622
0
  }
4623
4624
0
  state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4625
0
  SSVAL(state->vwv+0,0,fnum);
4626
4627
0
  subreq = cli_smb_send(state, ev, cli, SMBgetattrE, additional_flags, 0,
4628
0
            1, state->vwv, 0, NULL);
4629
0
  if (tevent_req_nomem(subreq, req)) {
4630
0
    return tevent_req_post(req, ev);
4631
0
  }
4632
0
  tevent_req_set_callback(subreq, cli_getattrE_done, req);
4633
0
  return req;
4634
0
}
4635
4636
static void cli_getattrE_done(struct tevent_req *subreq)
4637
0
{
4638
0
  struct tevent_req *req = tevent_req_callback_data(
4639
0
    subreq, struct tevent_req);
4640
0
  struct cli_getattrE_state *state = tevent_req_data(
4641
0
    req, struct cli_getattrE_state);
4642
0
  uint8_t wct;
4643
0
  uint16_t *vwv = NULL;
4644
0
  NTSTATUS status;
4645
4646
0
  status = cli_smb_recv(subreq, state, NULL, 11, &wct, &vwv,
4647
0
            NULL, NULL);
4648
0
  TALLOC_FREE(subreq);
4649
0
  if (tevent_req_nterror(req, status)) {
4650
0
    return;
4651
0
  }
4652
4653
0
  state->size = (off_t)IVAL(vwv+6,0);
4654
0
  state->attr = SVAL(vwv+10,0);
4655
0
  state->change_time = make_unix_date2(vwv+0, state->zone_offset);
4656
0
  state->access_time = make_unix_date2(vwv+2, state->zone_offset);
4657
0
  state->write_time = make_unix_date2(vwv+4, state->zone_offset);
4658
4659
0
  tevent_req_done(req);
4660
0
}
4661
4662
NTSTATUS cli_getattrE_recv(struct tevent_req *req,
4663
      uint32_t *pattr,
4664
      off_t *size,
4665
      time_t *change_time,
4666
      time_t *access_time,
4667
      time_t *write_time)
4668
0
{
4669
0
  struct cli_getattrE_state *state = tevent_req_data(
4670
0
        req, struct cli_getattrE_state);
4671
0
  NTSTATUS status;
4672
4673
0
  if (tevent_req_is_nterror(req, &status)) {
4674
0
    return status;
4675
0
  }
4676
0
  if (pattr) {
4677
0
    *pattr = state->attr;
4678
0
  }
4679
0
  if (size) {
4680
0
    *size = state->size;
4681
0
  }
4682
0
  if (change_time) {
4683
0
    *change_time = state->change_time;
4684
0
  }
4685
0
  if (access_time) {
4686
0
    *access_time = state->access_time;
4687
0
  }
4688
0
  if (write_time) {
4689
0
    *write_time = state->write_time;
4690
0
  }
4691
0
  return NT_STATUS_OK;
4692
0
}
4693
4694
/****************************************************************************
4695
 Do a SMBgetatr call
4696
****************************************************************************/
4697
4698
static void cli_getatr_done(struct tevent_req *subreq);
4699
4700
struct cli_getatr_state {
4701
  int zone_offset;
4702
  uint32_t attr;
4703
  off_t size;
4704
  time_t write_time;
4705
};
4706
4707
struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
4708
        struct tevent_context *ev,
4709
        struct cli_state *cli,
4710
        const char *fname)
4711
0
{
4712
0
  struct tevent_req *req = NULL, *subreq = NULL;
4713
0
  struct cli_getatr_state *state = NULL;
4714
0
  uint8_t additional_flags = 0;
4715
0
  uint16_t additional_flags2 = 0;
4716
0
  uint8_t *bytes = NULL;
4717
0
  char *fname_cp = NULL;
4718
4719
0
  req = tevent_req_create(mem_ctx, &state, struct cli_getatr_state);
4720
0
  if (req == NULL) {
4721
0
    return NULL;
4722
0
  }
4723
4724
0
  state->zone_offset = smb1cli_conn_server_time_zone(cli->conn);
4725
4726
0
  bytes = talloc_array(state, uint8_t, 1);
4727
0
  if (tevent_req_nomem(bytes, req)) {
4728
0
    return tevent_req_post(req, ev);
4729
0
  }
4730
  /*
4731
   * SMBgetatr on a DFS share must use DFS names.
4732
   */
4733
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
4734
0
  if (tevent_req_nomem(fname_cp, req)) {
4735
0
    return tevent_req_post(req, ev);
4736
0
  }
4737
0
  bytes[0] = 4;
4738
0
  bytes = smb_bytes_push_str(bytes,
4739
0
           smbXcli_conn_use_unicode(cli->conn),
4740
0
           fname_cp,
4741
0
           strlen(fname_cp)+1,
4742
0
           NULL);
4743
4744
0
  if (tevent_req_nomem(bytes, req)) {
4745
0
    return tevent_req_post(req, ev);
4746
0
  }
4747
4748
0
  if (clistr_is_previous_version_path(fname)) {
4749
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
4750
0
  }
4751
4752
0
  subreq = cli_smb_send(state, ev, cli, SMBgetatr, additional_flags,
4753
0
      additional_flags2,
4754
0
      0, NULL, talloc_get_size(bytes), bytes);
4755
0
  if (tevent_req_nomem(subreq, req)) {
4756
0
    return tevent_req_post(req, ev);
4757
0
  }
4758
0
  tevent_req_set_callback(subreq, cli_getatr_done, req);
4759
0
  return req;
4760
0
}
4761
4762
static void cli_getatr_done(struct tevent_req *subreq)
4763
0
{
4764
0
  struct tevent_req *req = tevent_req_callback_data(
4765
0
    subreq, struct tevent_req);
4766
0
  struct cli_getatr_state *state = tevent_req_data(
4767
0
    req, struct cli_getatr_state);
4768
0
  uint8_t wct;
4769
0
  uint16_t *vwv = NULL;
4770
0
  NTSTATUS status;
4771
4772
0
  status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
4773
0
            NULL);
4774
0
  TALLOC_FREE(subreq);
4775
0
  if (tevent_req_nterror(req, status)) {
4776
0
    return;
4777
0
  }
4778
4779
0
  state->attr = SVAL(vwv+0,0);
4780
0
  state->size = (off_t)IVAL(vwv+3,0);
4781
0
  state->write_time = make_unix_date3(vwv+1, state->zone_offset);
4782
4783
0
  tevent_req_done(req);
4784
0
}
4785
4786
NTSTATUS cli_getatr_recv(struct tevent_req *req,
4787
      uint32_t *pattr,
4788
      off_t *size,
4789
      time_t *write_time)
4790
0
{
4791
0
  struct cli_getatr_state *state = tevent_req_data(
4792
0
        req, struct cli_getatr_state);
4793
0
  NTSTATUS status;
4794
4795
0
  if (tevent_req_is_nterror(req, &status)) {
4796
0
    return status;
4797
0
  }
4798
0
  if (pattr) {
4799
0
    *pattr = state->attr;
4800
0
  }
4801
0
  if (size) {
4802
0
    *size = state->size;
4803
0
  }
4804
0
  if (write_time) {
4805
0
    *write_time = state->write_time;
4806
0
  }
4807
0
  return NT_STATUS_OK;
4808
0
}
4809
4810
NTSTATUS cli_getatr(struct cli_state *cli,
4811
      const char *fname,
4812
      uint32_t *pattr,
4813
      off_t *size,
4814
      time_t *write_time)
4815
0
{
4816
0
  TALLOC_CTX *frame = NULL;
4817
0
  struct tevent_context *ev = NULL;
4818
0
  struct tevent_req *req = NULL;
4819
0
  NTSTATUS status = NT_STATUS_OK;
4820
4821
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4822
0
    struct stat_ex sbuf = {
4823
0
      .st_ex_nlink = 0,
4824
0
    };
4825
0
    uint32_t attr;
4826
4827
0
    status = cli_smb2_qpathinfo_basic(cli, fname, &sbuf, &attr);
4828
0
    if (!NT_STATUS_IS_OK(status)) {
4829
0
      return status;
4830
0
    }
4831
4832
0
    if (pattr != NULL) {
4833
0
      *pattr = attr;
4834
0
    }
4835
0
    if (size != NULL) {
4836
0
      *size = sbuf.st_ex_size;
4837
0
    }
4838
0
    if (write_time != NULL) {
4839
0
      *write_time = sbuf.st_ex_mtime.tv_sec;
4840
0
    }
4841
0
    return NT_STATUS_OK;
4842
0
  }
4843
4844
0
  frame = talloc_stackframe();
4845
4846
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
4847
    /*
4848
     * Can't use sync call while an async call is in flight
4849
     */
4850
0
    status = NT_STATUS_INVALID_PARAMETER;
4851
0
    goto fail;
4852
0
  }
4853
4854
0
  ev = samba_tevent_context_init(frame);
4855
0
  if (ev == NULL) {
4856
0
    status = NT_STATUS_NO_MEMORY;
4857
0
    goto fail;
4858
0
  }
4859
4860
0
  req = cli_getatr_send(frame, ev, cli, fname);
4861
0
  if (req == NULL) {
4862
0
    status = NT_STATUS_NO_MEMORY;
4863
0
    goto fail;
4864
0
  }
4865
4866
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4867
0
    goto fail;
4868
0
  }
4869
4870
0
  status = cli_getatr_recv(req,
4871
0
        pattr,
4872
0
        size,
4873
0
        write_time);
4874
4875
0
 fail:
4876
0
  TALLOC_FREE(frame);
4877
0
  return status;
4878
0
}
4879
4880
/****************************************************************************
4881
 Do a SMBsetattrE call.
4882
****************************************************************************/
4883
4884
static void cli_setattrE_done(struct tevent_req *subreq);
4885
4886
struct cli_setattrE_state {
4887
  uint16_t vwv[7];
4888
};
4889
4890
struct tevent_req *cli_setattrE_send(TALLOC_CTX *mem_ctx,
4891
        struct tevent_context *ev,
4892
        struct cli_state *cli,
4893
        uint16_t fnum,
4894
        time_t change_time,
4895
        time_t access_time,
4896
        time_t write_time)
4897
0
{
4898
0
  struct tevent_req *req = NULL, *subreq = NULL;
4899
0
  struct cli_setattrE_state *state = NULL;
4900
0
  uint8_t additional_flags = 0;
4901
4902
0
  req = tevent_req_create(mem_ctx, &state, struct cli_setattrE_state);
4903
0
  if (req == NULL) {
4904
0
    return NULL;
4905
0
  }
4906
4907
0
  SSVAL(state->vwv+0, 0, fnum);
4908
0
  push_dos_date2((uint8_t *)&state->vwv[1], 0, change_time,
4909
0
           smb1cli_conn_server_time_zone(cli->conn));
4910
0
  push_dos_date2((uint8_t *)&state->vwv[3], 0, access_time,
4911
0
           smb1cli_conn_server_time_zone(cli->conn));
4912
0
  push_dos_date2((uint8_t *)&state->vwv[5], 0, write_time,
4913
0
           smb1cli_conn_server_time_zone(cli->conn));
4914
4915
0
  subreq = cli_smb_send(state, ev, cli, SMBsetattrE, additional_flags, 0,
4916
0
            7, state->vwv, 0, NULL);
4917
0
  if (tevent_req_nomem(subreq, req)) {
4918
0
    return tevent_req_post(req, ev);
4919
0
  }
4920
0
  tevent_req_set_callback(subreq, cli_setattrE_done, req);
4921
0
  return req;
4922
0
}
4923
4924
static void cli_setattrE_done(struct tevent_req *subreq)
4925
0
{
4926
0
  struct tevent_req *req = tevent_req_callback_data(
4927
0
    subreq, struct tevent_req);
4928
0
  NTSTATUS status;
4929
4930
0
  status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
4931
0
  TALLOC_FREE(subreq);
4932
0
  if (tevent_req_nterror(req, status)) {
4933
0
    return;
4934
0
  }
4935
0
  tevent_req_done(req);
4936
0
}
4937
4938
NTSTATUS cli_setattrE_recv(struct tevent_req *req)
4939
0
{
4940
0
  return tevent_req_simple_recv_ntstatus(req);
4941
0
}
4942
4943
NTSTATUS cli_setattrE(struct cli_state *cli,
4944
      uint16_t fnum,
4945
      time_t change_time,
4946
      time_t access_time,
4947
      time_t write_time)
4948
0
{
4949
0
  TALLOC_CTX *frame = NULL;
4950
0
  struct tevent_context *ev = NULL;
4951
0
  struct tevent_req *req = NULL;
4952
0
  NTSTATUS status = NT_STATUS_OK;
4953
4954
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
4955
0
    return cli_smb2_setattrE(cli,
4956
0
          fnum,
4957
0
          change_time,
4958
0
          access_time,
4959
0
          write_time);
4960
0
  }
4961
4962
0
  frame = talloc_stackframe();
4963
4964
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
4965
    /*
4966
     * Can't use sync call while an async call is in flight
4967
     */
4968
0
    status = NT_STATUS_INVALID_PARAMETER;
4969
0
    goto fail;
4970
0
  }
4971
4972
0
  ev = samba_tevent_context_init(frame);
4973
0
  if (ev == NULL) {
4974
0
    status = NT_STATUS_NO_MEMORY;
4975
0
    goto fail;
4976
0
  }
4977
4978
0
  req = cli_setattrE_send(frame, ev,
4979
0
      cli,
4980
0
      fnum,
4981
0
      change_time,
4982
0
      access_time,
4983
0
      write_time);
4984
4985
0
  if (req == NULL) {
4986
0
    status = NT_STATUS_NO_MEMORY;
4987
0
    goto fail;
4988
0
  }
4989
4990
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4991
0
    goto fail;
4992
0
  }
4993
4994
0
  status = cli_setattrE_recv(req);
4995
4996
0
 fail:
4997
0
  TALLOC_FREE(frame);
4998
0
  return status;
4999
0
}
5000
5001
/****************************************************************************
5002
 Do a SMBsetatr call.
5003
****************************************************************************/
5004
5005
static void cli_setatr_done(struct tevent_req *subreq);
5006
5007
struct cli_setatr_state {
5008
  uint16_t vwv[8];
5009
};
5010
5011
struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
5012
        struct tevent_context *ev,
5013
        struct cli_state *cli,
5014
        const char *fname,
5015
        uint32_t attr,
5016
        time_t mtime)
5017
0
{
5018
0
  struct tevent_req *req = NULL, *subreq = NULL;
5019
0
  struct cli_setatr_state *state = NULL;
5020
0
  uint8_t additional_flags = 0;
5021
0
  uint16_t additional_flags2 = 0;
5022
0
  uint8_t *bytes = NULL;
5023
0
  char *fname_cp = NULL;
5024
5025
0
  req = tevent_req_create(mem_ctx, &state, struct cli_setatr_state);
5026
0
  if (req == NULL) {
5027
0
    return NULL;
5028
0
  }
5029
5030
0
  if (attr & 0xFFFF0000) {
5031
    /*
5032
     * Don't allow attributes greater than
5033
     * 16-bits for a 16-bit protocol value.
5034
     */
5035
0
    if (tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER)) {
5036
0
      return tevent_req_post(req, ev);
5037
0
    }
5038
0
  }
5039
5040
0
  SSVAL(state->vwv+0, 0, attr);
5041
0
  push_dos_date3((uint8_t *)&state->vwv[1], 0, mtime, smb1cli_conn_server_time_zone(cli->conn));
5042
5043
0
  bytes = talloc_array(state, uint8_t, 1);
5044
0
  if (tevent_req_nomem(bytes, req)) {
5045
0
    return tevent_req_post(req, ev);
5046
0
  }
5047
  /*
5048
   * SMBsetatr on a DFS share must use DFS names.
5049
   */
5050
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
5051
0
  if (tevent_req_nomem(fname_cp, req)) {
5052
0
    return tevent_req_post(req, ev);
5053
0
  }
5054
0
  bytes[0] = 4;
5055
0
  bytes = smb_bytes_push_str(bytes,
5056
0
           smbXcli_conn_use_unicode(cli->conn),
5057
0
           fname_cp,
5058
0
           strlen(fname_cp)+1,
5059
0
           NULL);
5060
0
  if (tevent_req_nomem(bytes, req)) {
5061
0
    return tevent_req_post(req, ev);
5062
0
  }
5063
0
  bytes = talloc_realloc(state, bytes, uint8_t,
5064
0
      talloc_get_size(bytes)+1);
5065
0
  if (tevent_req_nomem(bytes, req)) {
5066
0
    return tevent_req_post(req, ev);
5067
0
  }
5068
5069
0
  bytes[talloc_get_size(bytes)-1] = 4;
5070
0
  bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "",
5071
0
           1, NULL);
5072
0
  if (tevent_req_nomem(bytes, req)) {
5073
0
    return tevent_req_post(req, ev);
5074
0
  }
5075
5076
0
  if (clistr_is_previous_version_path(fname)) {
5077
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
5078
0
  }
5079
5080
0
  subreq = cli_smb_send(state, ev, cli, SMBsetatr, additional_flags,
5081
0
      additional_flags2,
5082
0
      8, state->vwv, talloc_get_size(bytes), bytes);
5083
0
  if (tevent_req_nomem(subreq, req)) {
5084
0
    return tevent_req_post(req, ev);
5085
0
  }
5086
0
  tevent_req_set_callback(subreq, cli_setatr_done, req);
5087
0
  return req;
5088
0
}
5089
5090
static void cli_setatr_done(struct tevent_req *subreq)
5091
0
{
5092
0
  struct tevent_req *req = tevent_req_callback_data(
5093
0
    subreq, struct tevent_req);
5094
0
  NTSTATUS status;
5095
5096
0
  status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5097
0
  TALLOC_FREE(subreq);
5098
0
  if (tevent_req_nterror(req, status)) {
5099
0
    return;
5100
0
  }
5101
0
  tevent_req_done(req);
5102
0
}
5103
5104
NTSTATUS cli_setatr_recv(struct tevent_req *req)
5105
0
{
5106
0
  return tevent_req_simple_recv_ntstatus(req);
5107
0
}
5108
5109
NTSTATUS cli_setatr(struct cli_state *cli,
5110
    const char *fname,
5111
    uint32_t attr,
5112
    time_t mtime)
5113
0
{
5114
0
  TALLOC_CTX *frame = NULL;
5115
0
  struct tevent_context *ev = NULL;
5116
0
  struct tevent_req *req = NULL;
5117
0
  NTSTATUS status = NT_STATUS_OK;
5118
5119
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5120
0
    return cli_smb2_setatr(cli,
5121
0
          fname,
5122
0
          attr,
5123
0
          mtime);
5124
0
  }
5125
5126
0
  frame = talloc_stackframe();
5127
5128
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
5129
    /*
5130
     * Can't use sync call while an async call is in flight
5131
     */
5132
0
    status = NT_STATUS_INVALID_PARAMETER;
5133
0
    goto fail;
5134
0
  }
5135
5136
0
  ev = samba_tevent_context_init(frame);
5137
0
  if (ev == NULL) {
5138
0
    status = NT_STATUS_NO_MEMORY;
5139
0
    goto fail;
5140
0
  }
5141
5142
0
  req = cli_setatr_send(frame, ev, cli, fname, attr, mtime);
5143
0
  if (req == NULL) {
5144
0
    status = NT_STATUS_NO_MEMORY;
5145
0
    goto fail;
5146
0
  }
5147
5148
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5149
0
    goto fail;
5150
0
  }
5151
5152
0
  status = cli_setatr_recv(req);
5153
5154
0
 fail:
5155
0
  TALLOC_FREE(frame);
5156
0
  return status;
5157
0
}
5158
5159
/****************************************************************************
5160
 Check for existence of a dir.
5161
****************************************************************************/
5162
5163
static void cli_chkpath_done(struct tevent_req *subreq);
5164
static void cli_chkpath_opened(struct tevent_req *subreq);
5165
static void cli_chkpath_closed(struct tevent_req *subreq);
5166
5167
struct cli_chkpath_state {
5168
  struct tevent_context *ev;
5169
  struct cli_state *cli;
5170
};
5171
5172
struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
5173
          struct tevent_context *ev,
5174
          struct cli_state *cli,
5175
          const char *fname)
5176
0
{
5177
0
  struct tevent_req *req = NULL, *subreq = NULL;
5178
0
  struct cli_chkpath_state *state = NULL;
5179
0
  uint8_t additional_flags = 0;
5180
0
  uint16_t additional_flags2 = 0;
5181
0
  uint8_t *bytes = NULL;
5182
0
  char *fname_cp = NULL;
5183
5184
0
  req = tevent_req_create(mem_ctx, &state, struct cli_chkpath_state);
5185
0
  if (req == NULL) {
5186
0
    return NULL;
5187
0
  }
5188
0
  state->ev = ev;
5189
0
  state->cli = cli;
5190
5191
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) {
5192
0
    subreq = cli_ntcreate_send(
5193
0
      state,        /* mem_ctx */
5194
0
      state->ev,      /* ev */
5195
0
      state->cli,     /* cli */
5196
0
      fname,        /* fname */
5197
0
      0,        /* create_flags */
5198
0
      FILE_READ_ATTRIBUTES,   /* desired_access */
5199
0
      FILE_ATTRIBUTE_DIRECTORY, /* FileAttributes */
5200
0
      FILE_SHARE_READ|
5201
0
      FILE_SHARE_WRITE|
5202
0
      FILE_SHARE_DELETE, /* share_access */
5203
0
      FILE_OPEN, /* CreateDisposition */
5204
0
      FILE_DIRECTORY_FILE, /* CreateOptions */
5205
0
      SMB2_IMPERSONATION_IMPERSONATION,
5206
0
      0);   /* SecurityFlags */
5207
0
    if (tevent_req_nomem(subreq, req)) {
5208
0
      return tevent_req_post(req, ev);
5209
0
    }
5210
0
    tevent_req_set_callback(subreq, cli_chkpath_opened, req);
5211
0
    return req;
5212
0
  }
5213
5214
0
  bytes = talloc_array(state, uint8_t, 1);
5215
0
  if (tevent_req_nomem(bytes, req)) {
5216
0
    return tevent_req_post(req, ev);
5217
0
  }
5218
  /*
5219
   * SMBcheckpath on a DFS share must use DFS names.
5220
   */
5221
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
5222
0
  if (tevent_req_nomem(fname_cp, req)) {
5223
0
    return tevent_req_post(req, ev);
5224
0
  }
5225
0
  bytes[0] = 4;
5226
0
  bytes = smb_bytes_push_str(bytes,
5227
0
           smbXcli_conn_use_unicode(cli->conn),
5228
0
           fname_cp,
5229
0
           strlen(fname_cp)+1,
5230
0
           NULL);
5231
5232
0
  if (tevent_req_nomem(bytes, req)) {
5233
0
    return tevent_req_post(req, ev);
5234
0
  }
5235
5236
0
  if (clistr_is_previous_version_path(fname)) {
5237
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
5238
0
  }
5239
5240
0
  subreq = cli_smb_send(state, ev, cli, SMBcheckpath, additional_flags,
5241
0
      additional_flags2,
5242
0
      0, NULL, talloc_get_size(bytes), bytes);
5243
0
  if (tevent_req_nomem(subreq, req)) {
5244
0
    return tevent_req_post(req, ev);
5245
0
  }
5246
0
  tevent_req_set_callback(subreq, cli_chkpath_done, req);
5247
0
  return req;
5248
0
}
5249
5250
static void cli_chkpath_done(struct tevent_req *subreq)
5251
0
{
5252
0
  NTSTATUS status = cli_smb_recv(
5253
0
    subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
5254
0
  tevent_req_simple_finish_ntstatus(subreq, status);
5255
0
}
5256
5257
static void cli_chkpath_opened(struct tevent_req *subreq)
5258
0
{
5259
0
  struct tevent_req *req = tevent_req_callback_data(
5260
0
    subreq, struct tevent_req);
5261
0
  struct cli_chkpath_state *state = tevent_req_data(
5262
0
    req, struct cli_chkpath_state);
5263
0
  NTSTATUS status;
5264
0
  uint16_t fnum;
5265
5266
0
  status = cli_ntcreate_recv(subreq, &fnum, NULL);
5267
0
  TALLOC_FREE(subreq);
5268
0
  if (tevent_req_nterror(req, status)) {
5269
0
    return;
5270
0
  }
5271
5272
0
  subreq = cli_close_send(state, state->ev, state->cli, fnum, 0);
5273
0
  if (tevent_req_nomem(subreq, req)) {
5274
0
    return;
5275
0
  }
5276
0
  tevent_req_set_callback(subreq, cli_chkpath_closed, req);
5277
0
}
5278
5279
static void cli_chkpath_closed(struct tevent_req *subreq)
5280
0
{
5281
0
  NTSTATUS status = cli_close_recv(subreq);
5282
0
  tevent_req_simple_finish_ntstatus(subreq, status);
5283
0
}
5284
5285
NTSTATUS cli_chkpath_recv(struct tevent_req *req)
5286
0
{
5287
0
  return tevent_req_simple_recv_ntstatus(req);
5288
0
}
5289
5290
NTSTATUS cli_chkpath(struct cli_state *cli, const char *path)
5291
0
{
5292
0
  TALLOC_CTX *frame = NULL;
5293
0
  struct tevent_context *ev = NULL;
5294
0
  struct tevent_req *req = NULL;
5295
0
  char *path2 = NULL;
5296
0
  NTSTATUS status = NT_STATUS_OK;
5297
5298
0
  frame = talloc_stackframe();
5299
5300
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
5301
    /*
5302
     * Can't use sync call while an async call is in flight
5303
     */
5304
0
    status = NT_STATUS_INVALID_PARAMETER;
5305
0
    goto fail;
5306
0
  }
5307
5308
0
  path2 = talloc_strdup(frame, path);
5309
0
  if (!path2) {
5310
0
    status = NT_STATUS_NO_MEMORY;
5311
0
    goto fail;
5312
0
  }
5313
0
  trim_char(path2,'\0','\\');
5314
0
  if (!*path2) {
5315
0
    path2 = talloc_strdup(frame, "\\");
5316
0
    if (!path2) {
5317
0
      status = NT_STATUS_NO_MEMORY;
5318
0
      goto fail;
5319
0
    }
5320
0
  }
5321
5322
0
  ev = samba_tevent_context_init(frame);
5323
0
  if (ev == NULL) {
5324
0
    status = NT_STATUS_NO_MEMORY;
5325
0
    goto fail;
5326
0
  }
5327
5328
0
  req = cli_chkpath_send(frame, ev, cli, path2);
5329
0
  if (req == NULL) {
5330
0
    status = NT_STATUS_NO_MEMORY;
5331
0
    goto fail;
5332
0
  }
5333
5334
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5335
0
    goto fail;
5336
0
  }
5337
5338
0
  status = cli_chkpath_recv(req);
5339
0
 fail:
5340
0
  TALLOC_FREE(frame);
5341
0
  return status;
5342
0
}
5343
5344
/****************************************************************************
5345
 Query disk space.
5346
****************************************************************************/
5347
5348
static void cli_dskattr_done(struct tevent_req *subreq);
5349
5350
struct cli_dskattr_state {
5351
  int bsize;
5352
  int total;
5353
  int avail;
5354
};
5355
5356
struct tevent_req *cli_dskattr_send(TALLOC_CTX *mem_ctx,
5357
          struct tevent_context *ev,
5358
          struct cli_state *cli)
5359
0
{
5360
0
  struct tevent_req *req = NULL, *subreq = NULL;
5361
0
  struct cli_dskattr_state *state = NULL;
5362
0
  uint8_t additional_flags = 0;
5363
5364
0
  req = tevent_req_create(mem_ctx, &state, struct cli_dskattr_state);
5365
0
  if (req == NULL) {
5366
0
    return NULL;
5367
0
  }
5368
5369
0
  subreq = cli_smb_send(state, ev, cli, SMBdskattr, additional_flags, 0,
5370
0
            0, NULL, 0, NULL);
5371
0
  if (tevent_req_nomem(subreq, req)) {
5372
0
    return tevent_req_post(req, ev);
5373
0
  }
5374
0
  tevent_req_set_callback(subreq, cli_dskattr_done, req);
5375
0
  return req;
5376
0
}
5377
5378
static void cli_dskattr_done(struct tevent_req *subreq)
5379
0
{
5380
0
  struct tevent_req *req = tevent_req_callback_data(
5381
0
    subreq, struct tevent_req);
5382
0
  struct cli_dskattr_state *state = tevent_req_data(
5383
0
    req, struct cli_dskattr_state);
5384
0
  uint8_t wct;
5385
0
  uint16_t *vwv = NULL;
5386
0
  NTSTATUS status;
5387
5388
0
  status = cli_smb_recv(subreq, state, NULL, 4, &wct, &vwv, NULL,
5389
0
            NULL);
5390
0
  TALLOC_FREE(subreq);
5391
0
  if (tevent_req_nterror(req, status)) {
5392
0
    return;
5393
0
  }
5394
0
  state->bsize = SVAL(vwv+1, 0)*SVAL(vwv+2,0);
5395
0
  state->total = SVAL(vwv+0, 0);
5396
0
  state->avail = SVAL(vwv+3, 0);
5397
0
  tevent_req_done(req);
5398
0
}
5399
5400
NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *avail)
5401
0
{
5402
0
  struct cli_dskattr_state *state = tevent_req_data(
5403
0
        req, struct cli_dskattr_state);
5404
0
  NTSTATUS status;
5405
5406
0
  if (tevent_req_is_nterror(req, &status)) {
5407
0
    return status;
5408
0
  }
5409
0
  *bsize = state->bsize;
5410
0
  *total = state->total;
5411
0
  *avail = state->avail;
5412
0
  return NT_STATUS_OK;
5413
0
}
5414
5415
NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
5416
0
{
5417
0
  TALLOC_CTX *frame = NULL;
5418
0
  struct tevent_context *ev = NULL;
5419
0
  struct tevent_req *req = NULL;
5420
0
  NTSTATUS status = NT_STATUS_OK;
5421
5422
0
  frame = talloc_stackframe();
5423
5424
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
5425
    /*
5426
     * Can't use sync call while an async call is in flight
5427
     */
5428
0
    status = NT_STATUS_INVALID_PARAMETER;
5429
0
    goto fail;
5430
0
  }
5431
5432
0
  ev = samba_tevent_context_init(frame);
5433
0
  if (ev == NULL) {
5434
0
    status = NT_STATUS_NO_MEMORY;
5435
0
    goto fail;
5436
0
  }
5437
5438
0
  req = cli_dskattr_send(frame, ev, cli);
5439
0
  if (req == NULL) {
5440
0
    status = NT_STATUS_NO_MEMORY;
5441
0
    goto fail;
5442
0
  }
5443
5444
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5445
0
    goto fail;
5446
0
  }
5447
5448
0
  status = cli_dskattr_recv(req, bsize, total, avail);
5449
5450
0
 fail:
5451
0
  TALLOC_FREE(frame);
5452
0
  return status;
5453
0
}
5454
5455
NTSTATUS cli_disk_size(struct cli_state *cli, const char *path, uint64_t *bsize,
5456
           uint64_t *total, uint64_t *avail)
5457
0
{
5458
0
  uint64_t sectors_per_block;
5459
0
  uint64_t bytes_per_sector;
5460
0
  int old_bsize = 0, old_total = 0, old_avail = 0;
5461
0
  NTSTATUS status;
5462
5463
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5464
0
    return cli_smb2_dskattr(cli, path, bsize, total, avail);
5465
0
  }
5466
5467
  /*
5468
   * Try the trans2 disk full size info call first.
5469
   * We already use this in SMBC_fstatvfs_ctx().
5470
   * Ignore 'actual_available_units' as we only
5471
   * care about the quota for the caller.
5472
   */
5473
5474
0
  status = cli_get_fs_full_size_info(cli,
5475
0
      total,
5476
0
      avail,
5477
0
      NULL,
5478
0
      &sectors_per_block,
5479
0
      &bytes_per_sector);
5480
5481
        /* Try and cope will all variants of "we don't do this call"
5482
           and fall back to cli_dskattr. */
5483
5484
0
  if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_IMPLEMENTED) ||
5485
0
      NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED) ||
5486
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_INFO_CLASS) ||
5487
0
      NT_STATUS_EQUAL(status,NT_STATUS_PROCEDURE_NOT_FOUND) ||
5488
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_LEVEL) ||
5489
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_PARAMETER) ||
5490
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_REQUEST) ||
5491
0
      NT_STATUS_EQUAL(status,NT_STATUS_INVALID_DEVICE_STATE) ||
5492
0
      NT_STATUS_EQUAL(status,NT_STATUS_CTL_FILE_NOT_SUPPORTED) ||
5493
0
      NT_STATUS_EQUAL(status,NT_STATUS_UNSUCCESSFUL)) {
5494
0
    goto try_dskattr;
5495
0
  }
5496
5497
0
  if (!NT_STATUS_IS_OK(status)) {
5498
0
    return status;
5499
0
  }
5500
5501
0
  if (bsize) {
5502
0
    *bsize = sectors_per_block *
5503
0
       bytes_per_sector;
5504
0
  }
5505
5506
0
  return NT_STATUS_OK;
5507
5508
0
  try_dskattr:
5509
5510
  /* Old SMB1 core protocol fallback. */
5511
0
  status = cli_dskattr(cli, &old_bsize, &old_total, &old_avail);
5512
0
  if (!NT_STATUS_IS_OK(status)) {
5513
0
    return status;
5514
0
  }
5515
0
  if (bsize) {
5516
0
    *bsize = (uint64_t)old_bsize;
5517
0
  }
5518
0
  if (total) {
5519
0
    *total = (uint64_t)old_total;
5520
0
  }
5521
0
  if (avail) {
5522
0
    *avail = (uint64_t)old_avail;
5523
0
  }
5524
0
  return NT_STATUS_OK;
5525
0
}
5526
5527
/****************************************************************************
5528
 Create and open a temporary file.
5529
****************************************************************************/
5530
5531
static void cli_ctemp_done(struct tevent_req *subreq);
5532
5533
struct ctemp_state {
5534
  uint16_t vwv[3];
5535
  char *ret_path;
5536
  uint16_t fnum;
5537
};
5538
5539
struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
5540
        struct tevent_context *ev,
5541
        struct cli_state *cli,
5542
        const char *path)
5543
0
{
5544
0
  struct tevent_req *req = NULL, *subreq = NULL;
5545
0
  struct ctemp_state *state = NULL;
5546
0
  uint8_t additional_flags = 0;
5547
0
  uint16_t additional_flags2 = 0;
5548
0
  uint8_t *bytes = NULL;
5549
0
  char *path_cp = NULL;
5550
5551
0
  req = tevent_req_create(mem_ctx, &state, struct ctemp_state);
5552
0
  if (req == NULL) {
5553
0
    return NULL;
5554
0
  }
5555
5556
0
  SSVAL(state->vwv,0,0);
5557
0
  SIVALS(state->vwv+1,0,-1);
5558
5559
0
  bytes = talloc_array(state, uint8_t, 1);
5560
0
  if (tevent_req_nomem(bytes, req)) {
5561
0
    return tevent_req_post(req, ev);
5562
0
  }
5563
  /*
5564
   * SMBctemp on a DFS share must use DFS names.
5565
   */
5566
0
  path_cp = smb1_dfs_share_path(state, cli, path);
5567
0
  if (tevent_req_nomem(path_cp, req)) {
5568
0
    return tevent_req_post(req, ev);
5569
0
  }
5570
0
  bytes[0] = 4;
5571
0
  bytes = smb_bytes_push_str(bytes,
5572
0
           smbXcli_conn_use_unicode(cli->conn),
5573
0
           path_cp,
5574
0
           strlen(path_cp)+1,
5575
0
           NULL);
5576
0
  if (tevent_req_nomem(bytes, req)) {
5577
0
    return tevent_req_post(req, ev);
5578
0
  }
5579
5580
0
  if (clistr_is_previous_version_path(path)) {
5581
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
5582
0
  }
5583
5584
0
  subreq = cli_smb_send(state, ev, cli, SMBctemp, additional_flags,
5585
0
      additional_flags2,
5586
0
      3, state->vwv, talloc_get_size(bytes), bytes);
5587
0
  if (tevent_req_nomem(subreq, req)) {
5588
0
    return tevent_req_post(req, ev);
5589
0
  }
5590
0
  tevent_req_set_callback(subreq, cli_ctemp_done, req);
5591
0
  return req;
5592
0
}
5593
5594
static void cli_ctemp_done(struct tevent_req *subreq)
5595
0
{
5596
0
  struct tevent_req *req = tevent_req_callback_data(
5597
0
        subreq, struct tevent_req);
5598
0
  struct ctemp_state *state = tevent_req_data(
5599
0
        req, struct ctemp_state);
5600
0
  NTSTATUS status;
5601
0
  uint8_t wcnt;
5602
0
  uint16_t *vwv;
5603
0
  uint32_t num_bytes = 0;
5604
0
  uint8_t *bytes = NULL;
5605
5606
0
  status = cli_smb_recv(subreq, state, NULL, 1, &wcnt, &vwv,
5607
0
            &num_bytes, &bytes);
5608
0
  TALLOC_FREE(subreq);
5609
0
  if (tevent_req_nterror(req, status)) {
5610
0
    return;
5611
0
  }
5612
5613
0
  state->fnum = SVAL(vwv+0, 0);
5614
5615
  /* From W2K3, the result is just the ASCII name */
5616
0
  if (num_bytes < 2) {
5617
0
    tevent_req_nterror(req, NT_STATUS_DATA_ERROR);
5618
0
    return;
5619
0
  }
5620
5621
0
  if (pull_string_talloc(state,
5622
0
      NULL,
5623
0
      0,
5624
0
      &state->ret_path,
5625
0
      bytes,
5626
0
      num_bytes,
5627
0
      STR_ASCII) == 0) {
5628
0
    tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
5629
0
    return;
5630
0
  }
5631
0
  tevent_req_done(req);
5632
0
}
5633
5634
NTSTATUS cli_ctemp_recv(struct tevent_req *req,
5635
      TALLOC_CTX *ctx,
5636
      uint16_t *pfnum,
5637
      char **outfile)
5638
0
{
5639
0
  struct ctemp_state *state = tevent_req_data(req,
5640
0
      struct ctemp_state);
5641
0
  NTSTATUS status;
5642
5643
0
  if (tevent_req_is_nterror(req, &status)) {
5644
0
    return status;
5645
0
  }
5646
0
  *pfnum = state->fnum;
5647
0
  *outfile = talloc_strdup(ctx, state->ret_path);
5648
0
  if (!*outfile) {
5649
0
    return NT_STATUS_NO_MEMORY;
5650
0
  }
5651
0
  return NT_STATUS_OK;
5652
0
}
5653
5654
NTSTATUS cli_ctemp(struct cli_state *cli,
5655
      TALLOC_CTX *ctx,
5656
      const char *path,
5657
      uint16_t *pfnum,
5658
      char **out_path)
5659
0
{
5660
0
  TALLOC_CTX *frame = talloc_stackframe();
5661
0
  struct tevent_context *ev;
5662
0
  struct tevent_req *req;
5663
0
  NTSTATUS status = NT_STATUS_OK;
5664
5665
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
5666
    /*
5667
     * Can't use sync call while an async call is in flight
5668
     */
5669
0
    status = NT_STATUS_INVALID_PARAMETER;
5670
0
    goto fail;
5671
0
  }
5672
5673
0
  ev = samba_tevent_context_init(frame);
5674
0
  if (ev == NULL) {
5675
0
    status = NT_STATUS_NO_MEMORY;
5676
0
    goto fail;
5677
0
  }
5678
5679
0
  req = cli_ctemp_send(frame, ev, cli, path);
5680
0
  if (req == NULL) {
5681
0
    status = NT_STATUS_NO_MEMORY;
5682
0
    goto fail;
5683
0
  }
5684
5685
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
5686
0
    goto fail;
5687
0
  }
5688
5689
0
  status = cli_ctemp_recv(req, ctx, pfnum, out_path);
5690
5691
0
 fail:
5692
0
  TALLOC_FREE(frame);
5693
0
  return status;
5694
0
}
5695
5696
/*********************************************************
5697
 Set an extended attribute utility fn.
5698
*********************************************************/
5699
5700
static NTSTATUS cli_set_ea(struct cli_state *cli, uint16_t setup_val,
5701
         uint8_t *param, unsigned int param_len,
5702
         const char *ea_name,
5703
         const char *ea_val, size_t ea_len)
5704
0
{
5705
0
  uint16_t setup[1];
5706
0
  unsigned int data_len = 0;
5707
0
  uint8_t *data = NULL;
5708
0
  char *p;
5709
0
  size_t ea_namelen = strlen(ea_name);
5710
0
  NTSTATUS status;
5711
5712
0
  SSVAL(setup, 0, setup_val);
5713
5714
0
  if (ea_namelen == 0 && ea_len == 0) {
5715
0
    data_len = 4;
5716
0
    data = talloc_array(talloc_tos(),
5717
0
        uint8_t,
5718
0
        data_len);
5719
0
    if (!data) {
5720
0
      return NT_STATUS_NO_MEMORY;
5721
0
    }
5722
0
    p = (char *)data;
5723
0
    SIVAL(p,0,data_len);
5724
0
  } else {
5725
0
    data_len = 4 + 4 + ea_namelen + 1 + ea_len;
5726
0
    data = talloc_array(talloc_tos(),
5727
0
        uint8_t,
5728
0
        data_len);
5729
0
    if (!data) {
5730
0
      return NT_STATUS_NO_MEMORY;
5731
0
    }
5732
0
    p = (char *)data;
5733
0
    SIVAL(p,0,data_len);
5734
0
    p += 4;
5735
0
    SCVAL(p, 0, 0); /* EA flags. */
5736
0
    SCVAL(p, 1, ea_namelen);
5737
0
    SSVAL(p, 2, ea_len);
5738
0
    memcpy(p+4, ea_name, ea_namelen+1); /* Copy in the name. */
5739
0
    memcpy(p+4+ea_namelen+1, ea_val, ea_len);
5740
0
  }
5741
5742
  /*
5743
   * FIXME - if we want to do previous version path
5744
   * processing on an EA set call we need to turn this
5745
   * into calls to cli_trans_send()/cli_trans_recv()
5746
   * with a temporary event context, as cli_trans_send()
5747
   * have access to the additional_flags2 needed to
5748
   * send @GMT- paths. JRA.
5749
   */
5750
5751
0
  status = cli_trans(talloc_tos(), cli, SMBtrans2, NULL, -1, 0, 0,
5752
0
         setup, 1, 0,
5753
0
         param, param_len, 2,
5754
0
         data,  data_len, 0,
5755
0
         NULL,
5756
0
         NULL, 0, NULL, /* rsetup */
5757
0
         NULL, 0, NULL, /* rparam */
5758
0
         NULL, 0, NULL); /* rdata */
5759
0
  talloc_free(data);
5760
0
  return status;
5761
0
}
5762
5763
/*********************************************************
5764
 Set an extended attribute on a pathname.
5765
*********************************************************/
5766
5767
NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path,
5768
       const char *ea_name, const char *ea_val,
5769
       size_t ea_len)
5770
0
{
5771
0
  unsigned int param_len = 0;
5772
0
  uint8_t *param;
5773
0
  NTSTATUS status;
5774
0
  TALLOC_CTX *frame = NULL;
5775
0
  char *path_cp = NULL;
5776
5777
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5778
0
    return cli_smb2_set_ea_path(cli,
5779
0
          path,
5780
0
          ea_name,
5781
0
          ea_val,
5782
0
          ea_len);
5783
0
  }
5784
5785
0
  frame = talloc_stackframe();
5786
5787
0
  param = talloc_array(frame, uint8_t, 6);
5788
0
  if (!param) {
5789
0
    status = NT_STATUS_NO_MEMORY;
5790
0
    goto fail;
5791
0
  }
5792
0
  SSVAL(param,0,SMB_INFO_SET_EA);
5793
0
  SSVAL(param,2,0);
5794
0
  SSVAL(param,4,0);
5795
5796
  /*
5797
   * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
5798
   */
5799
0
  path_cp = smb1_dfs_share_path(frame, cli, path);
5800
0
  if (path_cp == NULL) {
5801
0
    status = NT_STATUS_NO_MEMORY;
5802
0
    goto fail;
5803
0
  }
5804
0
  param = trans2_bytes_push_str(param,
5805
0
              smbXcli_conn_use_unicode(cli->conn),
5806
0
              path_cp,
5807
0
              strlen(path_cp)+1,
5808
0
              NULL);
5809
0
  param_len = talloc_get_size(param);
5810
5811
0
  status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len,
5812
0
          ea_name, ea_val, ea_len);
5813
5814
0
  fail:
5815
5816
0
  TALLOC_FREE(frame);
5817
0
  return status;
5818
0
}
5819
5820
/*********************************************************
5821
 Set an extended attribute on an fnum.
5822
*********************************************************/
5823
5824
NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum,
5825
       const char *ea_name, const char *ea_val,
5826
       size_t ea_len)
5827
0
{
5828
0
  uint8_t param[6] = { 0, };
5829
5830
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
5831
0
    return cli_smb2_set_ea_fnum(cli,
5832
0
          fnum,
5833
0
          ea_name,
5834
0
          ea_val,
5835
0
          ea_len);
5836
0
  }
5837
5838
0
  SSVAL(param,0,fnum);
5839
0
  SSVAL(param,2,SMB_INFO_SET_EA);
5840
5841
0
  return cli_set_ea(cli, TRANSACT2_SETFILEINFO, param, 6,
5842
0
        ea_name, ea_val, ea_len);
5843
0
}
5844
5845
/*********************************************************
5846
 Get an extended attribute list utility fn.
5847
*********************************************************/
5848
5849
static bool parse_ea_blob(TALLOC_CTX *ctx, const uint8_t *rdata,
5850
        size_t rdata_len,
5851
        size_t *pnum_eas, struct ea_struct **pea_list)
5852
0
{
5853
0
  struct ea_struct *ea_list = NULL;
5854
0
  size_t num_eas;
5855
0
  size_t ea_size;
5856
0
  const uint8_t *p;
5857
5858
0
  if (rdata_len < 4) {
5859
0
    return false;
5860
0
  }
5861
5862
0
  ea_size = (size_t)IVAL(rdata,0);
5863
0
  if (ea_size > rdata_len) {
5864
0
    return false;
5865
0
  }
5866
5867
0
  if (ea_size == 0) {
5868
    /* No EA's present. */
5869
0
    *pnum_eas = 0;
5870
0
    *pea_list = NULL;
5871
0
    return true;
5872
0
  }
5873
5874
0
  p = rdata + 4;
5875
0
  ea_size -= 4;
5876
5877
  /* Validate the EA list and count it. */
5878
0
  for (num_eas = 0; ea_size >= 4; num_eas++) {
5879
0
    unsigned int ea_namelen = CVAL(p,1);
5880
0
    unsigned int ea_valuelen = SVAL(p,2);
5881
0
    if (ea_namelen == 0) {
5882
0
      return false;
5883
0
    }
5884
0
    if (4 + ea_namelen + 1 + ea_valuelen > ea_size) {
5885
0
      return false;
5886
0
    }
5887
0
    ea_size -= 4 + ea_namelen + 1 + ea_valuelen;
5888
0
    p += 4 + ea_namelen + 1 + ea_valuelen;
5889
0
  }
5890
5891
0
  if (num_eas == 0) {
5892
0
    *pnum_eas = 0;
5893
0
    *pea_list = NULL;
5894
0
    return true;
5895
0
  }
5896
5897
0
  *pnum_eas = num_eas;
5898
0
  if (!pea_list) {
5899
    /* Caller only wants number of EA's. */
5900
0
    return true;
5901
0
  }
5902
5903
0
  ea_list = talloc_array(ctx, struct ea_struct, num_eas);
5904
0
  if (!ea_list) {
5905
0
    return false;
5906
0
  }
5907
5908
0
  p = rdata + 4;
5909
5910
0
  for (num_eas = 0; num_eas < *pnum_eas; num_eas++ ) {
5911
0
    struct ea_struct *ea = &ea_list[num_eas];
5912
0
    fstring unix_ea_name;
5913
0
    unsigned int ea_namelen = CVAL(p,1);
5914
0
    unsigned int ea_valuelen = SVAL(p,2);
5915
5916
0
    ea->flags = CVAL(p,0);
5917
0
    unix_ea_name[0] = '\0';
5918
0
    pull_ascii(unix_ea_name, p + 4, sizeof(unix_ea_name), rdata_len - PTR_DIFF(p+4, rdata), STR_TERMINATE);
5919
0
    ea->name = talloc_strdup(ea_list, unix_ea_name);
5920
0
    if (!ea->name) {
5921
0
      goto fail;
5922
0
    }
5923
    /* Ensure the value is null terminated (in case it's a string). */
5924
0
    ea->value = data_blob_talloc(ea_list, NULL, ea_valuelen + 1);
5925
0
    if (!ea->value.data) {
5926
0
      goto fail;
5927
0
    }
5928
0
    if (ea_valuelen) {
5929
0
      memcpy(ea->value.data, p+4+ea_namelen+1, ea_valuelen);
5930
0
    }
5931
0
    ea->value.data[ea_valuelen] = 0;
5932
0
    ea->value.length--;
5933
0
    p += 4 + ea_namelen + 1 + ea_valuelen;
5934
0
  }
5935
5936
0
  *pea_list = ea_list;
5937
0
  return true;
5938
5939
0
fail:
5940
0
  TALLOC_FREE(ea_list);
5941
0
  return false;
5942
0
}
5943
5944
/*********************************************************
5945
 Get an extended attribute list from a pathname.
5946
*********************************************************/
5947
5948
struct cli_get_ea_list_path_state {
5949
  uint32_t num_data;
5950
  uint8_t *data;
5951
};
5952
5953
static void cli_get_ea_list_path_done(struct tevent_req *subreq);
5954
5955
struct tevent_req *cli_get_ea_list_path_send(TALLOC_CTX *mem_ctx,
5956
               struct tevent_context *ev,
5957
               struct cli_state *cli,
5958
               const char *fname)
5959
0
{
5960
0
  struct tevent_req *req, *subreq;
5961
0
  struct cli_get_ea_list_path_state *state;
5962
5963
0
  req = tevent_req_create(mem_ctx, &state,
5964
0
        struct cli_get_ea_list_path_state);
5965
0
  if (req == NULL) {
5966
0
    return NULL;
5967
0
  }
5968
0
  subreq = cli_qpathinfo_send(state, ev, cli, fname,
5969
0
            SMB_INFO_QUERY_ALL_EAS, 4,
5970
0
            CLI_BUFFER_SIZE);
5971
0
  if (tevent_req_nomem(subreq, req)) {
5972
0
    return tevent_req_post(req, ev);
5973
0
  }
5974
0
  tevent_req_set_callback(subreq, cli_get_ea_list_path_done, req);
5975
0
  return req;
5976
0
}
5977
5978
static void cli_get_ea_list_path_done(struct tevent_req *subreq)
5979
0
{
5980
0
  struct tevent_req *req = tevent_req_callback_data(
5981
0
        subreq, struct tevent_req);
5982
0
  struct cli_get_ea_list_path_state *state = tevent_req_data(
5983
0
    req, struct cli_get_ea_list_path_state);
5984
0
  NTSTATUS status;
5985
5986
0
  status = cli_qpathinfo_recv(subreq, state, &state->data,
5987
0
            &state->num_data);
5988
0
  TALLOC_FREE(subreq);
5989
0
  if (tevent_req_nterror(req, status)) {
5990
0
    return;
5991
0
  }
5992
0
  tevent_req_done(req);
5993
0
}
5994
5995
NTSTATUS cli_get_ea_list_path_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
5996
           size_t *pnum_eas, struct ea_struct **peas)
5997
0
{
5998
0
  struct cli_get_ea_list_path_state *state = tevent_req_data(
5999
0
    req, struct cli_get_ea_list_path_state);
6000
0
  NTSTATUS status;
6001
6002
0
  if (tevent_req_is_nterror(req, &status)) {
6003
0
    return status;
6004
0
  }
6005
0
  if (!parse_ea_blob(mem_ctx, state->data, state->num_data,
6006
0
         pnum_eas, peas)) {
6007
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
6008
0
  }
6009
0
  return NT_STATUS_OK;
6010
0
}
6011
6012
NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path,
6013
    TALLOC_CTX *ctx,
6014
    size_t *pnum_eas,
6015
    struct ea_struct **pea_list)
6016
0
{
6017
0
  TALLOC_CTX *frame = NULL;
6018
0
  struct tevent_context *ev = NULL;
6019
0
  struct tevent_req *req = NULL;
6020
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
6021
6022
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6023
0
    return cli_smb2_get_ea_list_path(cli,
6024
0
          path,
6025
0
          ctx,
6026
0
          pnum_eas,
6027
0
          pea_list);
6028
0
  }
6029
6030
0
  frame = talloc_stackframe();
6031
6032
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
6033
    /*
6034
     * Can't use sync call while an async call is in flight
6035
     */
6036
0
    status = NT_STATUS_INVALID_PARAMETER;
6037
0
    goto fail;
6038
0
  }
6039
0
  ev = samba_tevent_context_init(frame);
6040
0
  if (ev == NULL) {
6041
0
    goto fail;
6042
0
  }
6043
0
  req = cli_get_ea_list_path_send(frame, ev, cli, path);
6044
0
  if (req == NULL) {
6045
0
    goto fail;
6046
0
  }
6047
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6048
0
    goto fail;
6049
0
  }
6050
0
  status = cli_get_ea_list_path_recv(req, ctx, pnum_eas, pea_list);
6051
0
 fail:
6052
0
  TALLOC_FREE(frame);
6053
0
  return status;
6054
0
}
6055
6056
/****************************************************************************
6057
 Convert open "flags" arg to uint32_t on wire.
6058
****************************************************************************/
6059
6060
static uint32_t open_flags_to_wire(int flags)
6061
0
{
6062
0
  int open_mode = flags & O_ACCMODE;
6063
0
  uint32_t ret = 0;
6064
6065
0
  switch (open_mode) {
6066
0
    case O_WRONLY:
6067
0
      ret |= SMB_O_WRONLY;
6068
0
      break;
6069
0
    case O_RDWR:
6070
0
      ret |= SMB_O_RDWR;
6071
0
      break;
6072
0
    default:
6073
0
    case O_RDONLY:
6074
0
      ret |= SMB_O_RDONLY;
6075
0
      break;
6076
0
  }
6077
6078
0
  if (flags & O_CREAT) {
6079
0
    ret |= SMB_O_CREAT;
6080
0
  }
6081
0
  if (flags & O_EXCL) {
6082
0
    ret |= SMB_O_EXCL;
6083
0
  }
6084
0
  if (flags & O_TRUNC) {
6085
0
    ret |= SMB_O_TRUNC;
6086
0
  }
6087
0
#if defined(O_SYNC)
6088
0
  if (flags & O_SYNC) {
6089
0
    ret |= SMB_O_SYNC;
6090
0
  }
6091
0
#endif /* O_SYNC */
6092
0
  if (flags & O_APPEND) {
6093
0
    ret |= SMB_O_APPEND;
6094
0
  }
6095
0
#if defined(O_DIRECT)
6096
0
  if (flags & O_DIRECT) {
6097
0
    ret |= SMB_O_DIRECT;
6098
0
  }
6099
0
#endif
6100
0
#if defined(O_DIRECTORY)
6101
0
  if (flags & O_DIRECTORY) {
6102
0
    ret |= SMB_O_DIRECTORY;
6103
0
  }
6104
0
#endif
6105
0
  return ret;
6106
0
}
6107
6108
/****************************************************************************
6109
 Open a file - POSIX semantics. Returns fnum. Doesn't request oplock.
6110
****************************************************************************/
6111
6112
struct cli_posix_open_internal_state {
6113
  uint16_t setup;
6114
  uint8_t *param;
6115
  uint8_t data[18];
6116
  uint16_t fnum; /* Out */
6117
};
6118
6119
static void cli_posix_open_internal_done(struct tevent_req *subreq);
6120
6121
static struct tevent_req *cli_posix_open_internal_send(TALLOC_CTX *mem_ctx,
6122
          struct tevent_context *ev,
6123
          struct cli_state *cli,
6124
          const char *fname,
6125
          uint32_t wire_flags,
6126
          mode_t mode)
6127
0
{
6128
0
  struct tevent_req *req = NULL, *subreq = NULL;
6129
0
  struct cli_posix_open_internal_state *state = NULL;
6130
0
  char *fname_cp = NULL;
6131
6132
0
  req = tevent_req_create(
6133
0
    mem_ctx, &state, struct cli_posix_open_internal_state);
6134
0
  if (req == NULL) {
6135
0
    return NULL;
6136
0
  }
6137
6138
  /* Setup setup word. */
6139
0
  SSVAL(&state->setup, 0, TRANSACT2_SETPATHINFO);
6140
6141
  /* Setup param array. */
6142
0
  state->param = talloc_zero_array(state, uint8_t, 6);
6143
0
  if (tevent_req_nomem(state->param, req)) {
6144
0
    return tevent_req_post(req, ev);
6145
0
  }
6146
0
  SSVAL(state->param, 0, SMB_POSIX_PATH_OPEN);
6147
6148
  /*
6149
   * TRANSACT2_SETPATHINFO on a DFS share must use DFS names.
6150
   */
6151
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
6152
0
  if (tevent_req_nomem(fname_cp, req)) {
6153
0
    return tevent_req_post(req, ev);
6154
0
  }
6155
0
  state->param = trans2_bytes_push_str(
6156
0
    state->param,
6157
0
    smbXcli_conn_use_unicode(cli->conn),
6158
0
    fname_cp,
6159
0
    strlen(fname_cp)+1,
6160
0
    NULL);
6161
6162
0
  if (tevent_req_nomem(state->param, req)) {
6163
0
    return tevent_req_post(req, ev);
6164
0
  }
6165
6166
0
  SIVAL(state->data,0,0); /* No oplock. */
6167
0
  SIVAL(state->data,4,wire_flags);
6168
0
  SIVAL(state->data,8,unix_perms_to_wire(mode));
6169
0
  SIVAL(state->data,12,0); /* Top bits of perms currently undefined. */
6170
0
  SSVAL(state->data,16,SMB_NO_INFO_LEVEL_RETURNED); /* No info level returned. */
6171
6172
0
  subreq = cli_trans_send(state,      /* mem ctx. */
6173
0
        ev,     /* event ctx. */
6174
0
        cli,      /* cli_state. */
6175
0
        0,      /* additional_flags2 */
6176
0
        SMBtrans2,   /* cmd. */
6177
0
        NULL,     /* pipe name. */
6178
0
        -1,     /* fid. */
6179
0
        0,      /* function. */
6180
0
        0,      /* flags. */
6181
0
        &state->setup,    /* setup. */
6182
0
        1,      /* num setup uint16_t words. */
6183
0
        0,      /* max returned setup. */
6184
0
        state->param,   /* param. */
6185
0
        talloc_get_size(state->param),/* num param. */
6186
0
        2,      /* max returned param. */
6187
0
        state->data,    /* data. */
6188
0
        18,     /* num data. */
6189
0
        12);      /* max returned data. */
6190
6191
0
  if (tevent_req_nomem(subreq, req)) {
6192
0
    return tevent_req_post(req, ev);
6193
0
  }
6194
0
  tevent_req_set_callback(subreq, cli_posix_open_internal_done, req);
6195
0
  return req;
6196
0
}
6197
6198
static void cli_posix_open_internal_done(struct tevent_req *subreq)
6199
0
{
6200
0
  struct tevent_req *req = tevent_req_callback_data(
6201
0
    subreq, struct tevent_req);
6202
0
  struct cli_posix_open_internal_state *state = tevent_req_data(
6203
0
    req, struct cli_posix_open_internal_state);
6204
0
  NTSTATUS status;
6205
0
  uint8_t *data;
6206
0
  uint32_t num_data;
6207
6208
0
  status = cli_trans_recv(
6209
0
    subreq,
6210
0
    state,
6211
0
    NULL,
6212
0
    NULL,
6213
0
    0,
6214
0
    NULL,
6215
0
    NULL,
6216
0
    0,
6217
0
    NULL,
6218
0
    &data,
6219
0
    12,
6220
0
    &num_data);
6221
0
  TALLOC_FREE(subreq);
6222
0
  if (tevent_req_nterror(req, status)) {
6223
0
    return;
6224
0
  }
6225
0
  state->fnum = SVAL(data,2);
6226
0
  tevent_req_done(req);
6227
0
}
6228
6229
static NTSTATUS cli_posix_open_internal_recv(struct tevent_req *req,
6230
               uint16_t *pfnum)
6231
0
{
6232
0
  struct cli_posix_open_internal_state *state = tevent_req_data(
6233
0
    req, struct cli_posix_open_internal_state);
6234
0
  NTSTATUS status;
6235
6236
0
  if (tevent_req_is_nterror(req, &status)) {
6237
0
    return status;
6238
0
  }
6239
0
  *pfnum = state->fnum;
6240
0
  return NT_STATUS_OK;
6241
0
}
6242
6243
struct cli_posix_open_state {
6244
  uint16_t fnum;
6245
};
6246
6247
static void cli_posix_open_done(struct tevent_req *subreq);
6248
6249
struct tevent_req *cli_posix_open_send(TALLOC_CTX *mem_ctx,
6250
          struct tevent_context *ev,
6251
          struct cli_state *cli,
6252
          const char *fname,
6253
          int flags,
6254
          mode_t mode)
6255
0
{
6256
0
  struct tevent_req *req = NULL, *subreq = NULL;
6257
0
  struct cli_posix_open_state *state = NULL;
6258
0
  uint32_t wire_flags;
6259
6260
0
  req = tevent_req_create(mem_ctx, &state,
6261
0
        struct cli_posix_open_state);
6262
0
  if (req == NULL) {
6263
0
    return NULL;
6264
0
  }
6265
6266
0
  wire_flags = open_flags_to_wire(flags);
6267
6268
0
  subreq = cli_posix_open_internal_send(
6269
0
    mem_ctx, ev, cli, fname, wire_flags, mode);
6270
0
  if (tevent_req_nomem(subreq, req)) {
6271
0
    return tevent_req_post(req, ev);
6272
0
  }
6273
0
  tevent_req_set_callback(subreq, cli_posix_open_done, req);
6274
0
  return req;
6275
0
}
6276
6277
static void cli_posix_open_done(struct tevent_req *subreq)
6278
0
{
6279
0
  struct tevent_req *req = tevent_req_callback_data(
6280
0
    subreq, struct tevent_req);
6281
0
  struct cli_posix_open_state *state = tevent_req_data(
6282
0
    req, struct cli_posix_open_state);
6283
0
  NTSTATUS status;
6284
6285
0
  status = cli_posix_open_internal_recv(subreq, &state->fnum);
6286
0
  tevent_req_simple_finish_ntstatus(subreq, status);
6287
0
}
6288
6289
NTSTATUS cli_posix_open_recv(struct tevent_req *req, uint16_t *pfnum)
6290
0
{
6291
0
  struct cli_posix_open_state *state = tevent_req_data(
6292
0
    req, struct cli_posix_open_state);
6293
0
  NTSTATUS status;
6294
6295
0
  if (tevent_req_is_nterror(req, &status)) {
6296
0
    return status;
6297
0
  }
6298
0
  *pfnum = state->fnum;
6299
0
  return NT_STATUS_OK;
6300
0
}
6301
6302
/****************************************************************************
6303
 Open - POSIX semantics. Doesn't request oplock.
6304
****************************************************************************/
6305
6306
NTSTATUS cli_posix_open(struct cli_state *cli, const char *fname,
6307
      int flags, mode_t mode, uint16_t *pfnum)
6308
0
{
6309
6310
0
  TALLOC_CTX *frame = talloc_stackframe();
6311
0
  struct tevent_context *ev = NULL;
6312
0
  struct tevent_req *req = NULL;
6313
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
6314
6315
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
6316
    /*
6317
     * Can't use sync call while an async call is in flight
6318
     */
6319
0
    status = NT_STATUS_INVALID_PARAMETER;
6320
0
    goto fail;
6321
0
  }
6322
0
  ev = samba_tevent_context_init(frame);
6323
0
  if (ev == NULL) {
6324
0
    goto fail;
6325
0
  }
6326
0
  req = cli_posix_open_send(
6327
0
    frame, ev, cli, fname, flags, mode);
6328
0
  if (req == NULL) {
6329
0
    goto fail;
6330
0
  }
6331
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6332
0
    goto fail;
6333
0
  }
6334
0
  status = cli_posix_open_recv(req, pfnum);
6335
0
 fail:
6336
0
  TALLOC_FREE(frame);
6337
0
  return status;
6338
0
}
6339
6340
struct cli_posix_mkdir_state {
6341
  struct tevent_context *ev;
6342
  struct cli_state *cli;
6343
};
6344
6345
static void cli_posix_mkdir_done(struct tevent_req *subreq);
6346
6347
struct tevent_req *cli_posix_mkdir_send(TALLOC_CTX *mem_ctx,
6348
          struct tevent_context *ev,
6349
          struct cli_state *cli,
6350
          const char *fname,
6351
          mode_t mode)
6352
0
{
6353
0
  struct tevent_req *req = NULL, *subreq = NULL;
6354
0
  struct cli_posix_mkdir_state *state = NULL;
6355
0
  uint32_t wire_flags;
6356
6357
0
  req = tevent_req_create(
6358
0
    mem_ctx, &state, struct cli_posix_mkdir_state);
6359
0
  if (req == NULL) {
6360
0
    return NULL;
6361
0
  }
6362
0
  state->ev = ev;
6363
0
  state->cli = cli;
6364
6365
0
  wire_flags = SMB_O_CREAT | SMB_O_DIRECTORY;
6366
6367
0
  subreq = cli_posix_open_internal_send(
6368
0
    mem_ctx, ev, cli, fname, wire_flags, mode);
6369
0
  if (tevent_req_nomem(subreq, req)) {
6370
0
    return tevent_req_post(req, ev);
6371
0
  }
6372
0
  tevent_req_set_callback(subreq, cli_posix_mkdir_done, req);
6373
0
  return req;
6374
0
}
6375
6376
static void cli_posix_mkdir_done(struct tevent_req *subreq)
6377
0
{
6378
0
  struct tevent_req *req = tevent_req_callback_data(
6379
0
    subreq, struct tevent_req);
6380
0
  NTSTATUS status;
6381
0
  uint16_t fnum;
6382
6383
0
  status = cli_posix_open_internal_recv(subreq, &fnum);
6384
0
  TALLOC_FREE(subreq);
6385
0
  if (tevent_req_nterror(req, status)) {
6386
0
    return;
6387
0
  }
6388
0
  tevent_req_done(req);
6389
0
}
6390
6391
NTSTATUS cli_posix_mkdir_recv(struct tevent_req *req)
6392
0
{
6393
0
  return tevent_req_simple_recv_ntstatus(req);
6394
0
}
6395
6396
NTSTATUS cli_posix_mkdir(struct cli_state *cli, const char *fname, mode_t mode)
6397
0
{
6398
0
  TALLOC_CTX *frame = talloc_stackframe();
6399
0
  struct tevent_context *ev = NULL;
6400
0
  struct tevent_req *req = NULL;
6401
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
6402
6403
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
6404
    /*
6405
     * Can't use sync call while an async call is in flight
6406
     */
6407
0
    status = NT_STATUS_INVALID_PARAMETER;
6408
0
    goto fail;
6409
0
  }
6410
6411
0
  ev = samba_tevent_context_init(frame);
6412
0
  if (ev == NULL) {
6413
0
    goto fail;
6414
0
  }
6415
0
  req = cli_posix_mkdir_send(
6416
0
    frame, ev, cli, fname, mode);
6417
0
  if (req == NULL) {
6418
0
    goto fail;
6419
0
  }
6420
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6421
0
    goto fail;
6422
0
  }
6423
0
  status = cli_posix_mkdir_recv(req);
6424
0
 fail:
6425
0
  TALLOC_FREE(frame);
6426
0
  return status;
6427
0
}
6428
6429
/****************************************************************************
6430
 unlink or rmdir - POSIX semantics.
6431
****************************************************************************/
6432
6433
struct cli_posix_unlink_internal_state {
6434
  uint8_t data[2];
6435
};
6436
6437
static void cli_posix_unlink_internal_done(struct tevent_req *subreq);
6438
6439
static struct tevent_req *cli_posix_unlink_internal_send(TALLOC_CTX *mem_ctx,
6440
          struct tevent_context *ev,
6441
          struct cli_state *cli,
6442
          const char *fname,
6443
          uint16_t level)
6444
0
{
6445
0
  struct tevent_req *req = NULL, *subreq = NULL;
6446
0
  struct cli_posix_unlink_internal_state *state = NULL;
6447
6448
0
  req = tevent_req_create(mem_ctx, &state,
6449
0
        struct cli_posix_unlink_internal_state);
6450
0
  if (req == NULL) {
6451
0
    return NULL;
6452
0
  }
6453
6454
  /* Setup data word. */
6455
0
  SSVAL(state->data, 0, level);
6456
6457
0
  subreq = cli_setpathinfo_send(state, ev, cli,
6458
0
              SMB_POSIX_PATH_UNLINK,
6459
0
              fname,
6460
0
              state->data, sizeof(state->data));
6461
0
  if (tevent_req_nomem(subreq, req)) {
6462
0
    return tevent_req_post(req, ev);
6463
0
  }
6464
0
  tevent_req_set_callback(subreq, cli_posix_unlink_internal_done, req);
6465
0
  return req;
6466
0
}
6467
6468
static void cli_posix_unlink_internal_done(struct tevent_req *subreq)
6469
0
{
6470
0
  NTSTATUS status = cli_setpathinfo_recv(subreq);
6471
0
  tevent_req_simple_finish_ntstatus(subreq, status);
6472
0
}
6473
6474
static NTSTATUS cli_posix_unlink_internal_recv(struct tevent_req *req)
6475
0
{
6476
0
  return tevent_req_simple_recv_ntstatus(req);
6477
0
}
6478
6479
struct cli_posix_unlink_state {
6480
  uint8_t dummy;
6481
};
6482
6483
static void cli_posix_unlink_done(struct tevent_req *subreq);
6484
6485
struct tevent_req *cli_posix_unlink_send(TALLOC_CTX *mem_ctx,
6486
          struct tevent_context *ev,
6487
          struct cli_state *cli,
6488
          const char *fname)
6489
0
{
6490
0
  struct tevent_req *req = NULL, *subreq = NULL;
6491
0
  struct cli_posix_unlink_state *state;
6492
6493
0
  req = tevent_req_create(
6494
0
    mem_ctx, &state, struct cli_posix_unlink_state);
6495
0
  if (req == NULL) {
6496
0
    return NULL;
6497
0
  }
6498
0
  subreq = cli_posix_unlink_internal_send(
6499
0
    mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_FILE_TARGET);
6500
0
  if (tevent_req_nomem(subreq, req)) {
6501
0
    return tevent_req_post(req, ev);
6502
0
  }
6503
0
  tevent_req_set_callback(subreq, cli_posix_unlink_done, req);
6504
0
  return req;
6505
0
}
6506
6507
static void cli_posix_unlink_done(struct tevent_req *subreq)
6508
0
{
6509
0
  NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6510
0
  tevent_req_simple_finish_ntstatus(subreq, status);
6511
0
}
6512
6513
NTSTATUS cli_posix_unlink_recv(struct tevent_req *req)
6514
0
{
6515
0
  return tevent_req_simple_recv_ntstatus(req);
6516
0
}
6517
6518
/****************************************************************************
6519
 unlink - POSIX semantics.
6520
****************************************************************************/
6521
6522
NTSTATUS cli_posix_unlink(struct cli_state *cli, const char *fname)
6523
0
{
6524
0
  TALLOC_CTX *frame = talloc_stackframe();
6525
0
  struct tevent_context *ev = NULL;
6526
0
  struct tevent_req *req = NULL;
6527
0
  NTSTATUS status = NT_STATUS_OK;
6528
6529
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
6530
    /*
6531
     * Can't use sync call while an async call is in flight
6532
     */
6533
0
    status = NT_STATUS_INVALID_PARAMETER;
6534
0
    goto fail;
6535
0
  }
6536
6537
0
  ev = samba_tevent_context_init(frame);
6538
0
  if (ev == NULL) {
6539
0
    status = NT_STATUS_NO_MEMORY;
6540
0
    goto fail;
6541
0
  }
6542
6543
0
  req = cli_posix_unlink_send(frame,
6544
0
        ev,
6545
0
        cli,
6546
0
        fname);
6547
0
  if (req == NULL) {
6548
0
    status = NT_STATUS_NO_MEMORY;
6549
0
    goto fail;
6550
0
  }
6551
6552
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6553
0
    goto fail;
6554
0
  }
6555
6556
0
  status = cli_posix_unlink_recv(req);
6557
6558
0
 fail:
6559
0
  TALLOC_FREE(frame);
6560
0
  return status;
6561
0
}
6562
6563
/****************************************************************************
6564
 rmdir - POSIX semantics.
6565
****************************************************************************/
6566
6567
struct cli_posix_rmdir_state {
6568
  uint8_t dummy;
6569
};
6570
6571
static void cli_posix_rmdir_done(struct tevent_req *subreq);
6572
6573
struct tevent_req *cli_posix_rmdir_send(TALLOC_CTX *mem_ctx,
6574
          struct tevent_context *ev,
6575
          struct cli_state *cli,
6576
          const char *fname)
6577
0
{
6578
0
  struct tevent_req *req = NULL, *subreq = NULL;
6579
0
  struct cli_posix_rmdir_state *state;
6580
6581
0
  req = tevent_req_create(mem_ctx, &state, struct cli_posix_rmdir_state);
6582
0
  if (req == NULL) {
6583
0
    return NULL;
6584
0
  }
6585
0
  subreq = cli_posix_unlink_internal_send(
6586
0
    mem_ctx, ev, cli, fname, SMB_POSIX_UNLINK_DIRECTORY_TARGET);
6587
0
  if (tevent_req_nomem(subreq, req)) {
6588
0
    return tevent_req_post(req, ev);
6589
0
  }
6590
0
  tevent_req_set_callback(subreq, cli_posix_rmdir_done, req);
6591
0
  return req;
6592
0
}
6593
6594
static void cli_posix_rmdir_done(struct tevent_req *subreq)
6595
0
{
6596
0
  NTSTATUS status = cli_posix_unlink_internal_recv(subreq);
6597
0
  tevent_req_simple_finish_ntstatus(subreq, status);
6598
0
}
6599
6600
NTSTATUS cli_posix_rmdir_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx)
6601
0
{
6602
0
  return tevent_req_simple_recv_ntstatus(req);
6603
0
}
6604
6605
NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname)
6606
0
{
6607
0
  TALLOC_CTX *frame = talloc_stackframe();
6608
0
  struct tevent_context *ev = NULL;
6609
0
  struct tevent_req *req = NULL;
6610
0
  NTSTATUS status = NT_STATUS_OK;
6611
6612
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
6613
    /*
6614
     * Can't use sync call while an async call is in flight
6615
     */
6616
0
    status = NT_STATUS_INVALID_PARAMETER;
6617
0
    goto fail;
6618
0
  }
6619
6620
0
  ev = samba_tevent_context_init(frame);
6621
0
  if (ev == NULL) {
6622
0
    status = NT_STATUS_NO_MEMORY;
6623
0
    goto fail;
6624
0
  }
6625
6626
0
  req = cli_posix_rmdir_send(frame,
6627
0
        ev,
6628
0
        cli,
6629
0
        fname);
6630
0
  if (req == NULL) {
6631
0
    status = NT_STATUS_NO_MEMORY;
6632
0
    goto fail;
6633
0
  }
6634
6635
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6636
0
    goto fail;
6637
0
  }
6638
6639
0
  status = cli_posix_rmdir_recv(req, frame);
6640
6641
0
 fail:
6642
0
  TALLOC_FREE(frame);
6643
0
  return status;
6644
0
}
6645
6646
/****************************************************************************
6647
 filechangenotify
6648
****************************************************************************/
6649
6650
struct cli_notify_state {
6651
  struct tevent_req *subreq;
6652
  uint16_t setup[4];
6653
  uint32_t num_changes;
6654
  struct notify_change *changes;
6655
};
6656
6657
static void cli_notify_done(struct tevent_req *subreq);
6658
static void cli_notify_done_smb2(struct tevent_req *subreq);
6659
static bool cli_notify_cancel(struct tevent_req *req);
6660
6661
struct tevent_req *cli_notify_send(TALLOC_CTX *mem_ctx,
6662
           struct tevent_context *ev,
6663
           struct cli_state *cli, uint16_t fnum,
6664
           uint32_t buffer_size,
6665
           uint32_t completion_filter, bool recursive)
6666
0
{
6667
0
  struct tevent_req *req;
6668
0
  struct cli_notify_state *state;
6669
0
  unsigned old_timeout;
6670
6671
0
  req = tevent_req_create(mem_ctx, &state, struct cli_notify_state);
6672
0
  if (req == NULL) {
6673
0
    return NULL;
6674
0
  }
6675
6676
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6677
    /*
6678
     * Notifies should not time out
6679
     */
6680
0
    old_timeout = cli_set_timeout(cli, 0);
6681
6682
0
    state->subreq = cli_smb2_notify_send(
6683
0
      state,
6684
0
      ev,
6685
0
      cli,
6686
0
      fnum,
6687
0
      buffer_size,
6688
0
      completion_filter,
6689
0
      recursive);
6690
6691
0
    cli_set_timeout(cli, old_timeout);
6692
6693
0
    if (tevent_req_nomem(state->subreq, req)) {
6694
0
      return tevent_req_post(req, ev);
6695
0
    }
6696
0
    tevent_req_set_callback(
6697
0
      state->subreq, cli_notify_done_smb2, req);
6698
0
    goto done;
6699
0
  }
6700
6701
0
  SIVAL(state->setup, 0, completion_filter);
6702
0
  SSVAL(state->setup, 4, fnum);
6703
0
  SSVAL(state->setup, 6, recursive);
6704
6705
  /*
6706
   * Notifies should not time out
6707
   */
6708
0
  old_timeout = cli_set_timeout(cli, 0);
6709
6710
0
  state->subreq = cli_trans_send(
6711
0
    state,      /* mem ctx. */
6712
0
    ev,     /* event ctx. */
6713
0
    cli,      /* cli_state. */
6714
0
    0,      /* additional_flags2 */
6715
0
    SMBnttrans,   /* cmd. */
6716
0
    NULL,     /* pipe name. */
6717
0
    -1,     /* fid. */
6718
0
    NT_TRANSACT_NOTIFY_CHANGE, /* function. */
6719
0
    0,      /* flags. */
6720
0
    (uint16_t *)state->setup, /* setup. */
6721
0
    4,      /* num setup uint16_t words. */
6722
0
    0,      /* max returned setup. */
6723
0
    NULL,     /* param. */
6724
0
    0,      /* num param. */
6725
0
    buffer_size,    /* max returned param. */
6726
0
    NULL,     /* data. */
6727
0
    0,      /* num data. */
6728
0
    0);     /* max returned data. */
6729
6730
0
  cli_set_timeout(cli, old_timeout);
6731
6732
0
  if (tevent_req_nomem(state->subreq, req)) {
6733
0
    return tevent_req_post(req, ev);
6734
0
  }
6735
0
  tevent_req_set_callback(state->subreq, cli_notify_done, req);
6736
0
done:
6737
0
  tevent_req_set_cancel_fn(req, cli_notify_cancel);
6738
0
  return req;
6739
0
}
6740
6741
static bool cli_notify_cancel(struct tevent_req *req)
6742
0
{
6743
0
  struct cli_notify_state *state = tevent_req_data(
6744
0
    req, struct cli_notify_state);
6745
0
  bool ok;
6746
6747
0
  ok = tevent_req_cancel(state->subreq);
6748
0
  return ok;
6749
0
}
6750
6751
static void cli_notify_done(struct tevent_req *subreq)
6752
0
{
6753
0
  struct tevent_req *req = tevent_req_callback_data(
6754
0
    subreq, struct tevent_req);
6755
0
  struct cli_notify_state *state = tevent_req_data(
6756
0
    req, struct cli_notify_state);
6757
0
  NTSTATUS status;
6758
0
  uint8_t *params;
6759
0
  uint32_t i, ofs, num_params;
6760
0
  uint16_t flags2;
6761
6762
0
  status = cli_trans_recv(subreq, talloc_tos(), &flags2, NULL, 0, NULL,
6763
0
        &params, 0, &num_params, NULL, 0, NULL);
6764
0
  TALLOC_FREE(subreq);
6765
0
  state->subreq = NULL;
6766
0
  if (tevent_req_nterror(req, status)) {
6767
0
    DEBUG(10, ("cli_trans_recv returned %s\n", nt_errstr(status)));
6768
0
    return;
6769
0
  }
6770
6771
0
  state->num_changes = 0;
6772
0
  ofs = 0;
6773
6774
0
  while (num_params - ofs > 12) {
6775
0
    uint32_t next = IVAL(params, ofs);
6776
0
    state->num_changes += 1;
6777
6778
0
    if ((next == 0) || (ofs+next >= num_params)) {
6779
0
      break;
6780
0
    }
6781
0
    ofs += next;
6782
0
  }
6783
6784
0
  state->changes = talloc_array(state, struct notify_change,
6785
0
              state->num_changes);
6786
0
  if (tevent_req_nomem(state->changes, req)) {
6787
0
    TALLOC_FREE(params);
6788
0
    return;
6789
0
  }
6790
6791
0
  ofs = 0;
6792
6793
0
  for (i=0; i<state->num_changes; i++) {
6794
0
    uint32_t next = IVAL(params, ofs);
6795
0
    uint32_t len = IVAL(params, ofs+8);
6796
0
    ssize_t ret;
6797
0
    char *name;
6798
6799
0
    if (smb_buffer_oob(num_params, ofs + 12, len)) {
6800
0
      TALLOC_FREE(params);
6801
0
      tevent_req_nterror(
6802
0
        req, NT_STATUS_INVALID_NETWORK_RESPONSE);
6803
0
      return;
6804
0
    }
6805
6806
0
    state->changes[i].action = IVAL(params, ofs+4);
6807
0
    ret = pull_string_talloc(state->changes,
6808
0
           (char *)params,
6809
0
           flags2,
6810
0
           &name,
6811
0
           params+ofs+12,
6812
0
           len,
6813
0
           STR_TERMINATE|STR_UNICODE);
6814
0
    if (ret == -1) {
6815
0
      TALLOC_FREE(params);
6816
0
      tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
6817
0
      return;
6818
0
    }
6819
0
    state->changes[i].name = name;
6820
0
    ofs += next;
6821
0
  }
6822
6823
0
  TALLOC_FREE(params);
6824
0
  tevent_req_done(req);
6825
0
}
6826
6827
static void cli_notify_done_smb2(struct tevent_req *subreq)
6828
0
{
6829
0
  struct tevent_req *req = tevent_req_callback_data(
6830
0
    subreq, struct tevent_req);
6831
0
  struct cli_notify_state *state = tevent_req_data(
6832
0
    req, struct cli_notify_state);
6833
0
  NTSTATUS status;
6834
6835
0
  status = cli_smb2_notify_recv(
6836
0
    subreq,
6837
0
    state,
6838
0
    &state->changes,
6839
0
    &state->num_changes);
6840
0
  TALLOC_FREE(subreq);
6841
0
  if (tevent_req_nterror(req, status)) {
6842
0
    return;
6843
0
  }
6844
0
  tevent_req_done(req);
6845
0
}
6846
6847
NTSTATUS cli_notify_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
6848
       uint32_t *pnum_changes,
6849
       struct notify_change **pchanges)
6850
0
{
6851
0
  struct cli_notify_state *state = tevent_req_data(
6852
0
    req, struct cli_notify_state);
6853
0
  NTSTATUS status;
6854
6855
0
  if (tevent_req_is_nterror(req, &status)) {
6856
0
    return status;
6857
0
  }
6858
6859
0
  *pnum_changes = state->num_changes;
6860
0
  *pchanges = talloc_move(mem_ctx, &state->changes);
6861
0
  return NT_STATUS_OK;
6862
0
}
6863
6864
NTSTATUS cli_notify(struct cli_state *cli, uint16_t fnum, uint32_t buffer_size,
6865
        uint32_t completion_filter, bool recursive,
6866
        TALLOC_CTX *mem_ctx, uint32_t *pnum_changes,
6867
        struct notify_change **pchanges)
6868
0
{
6869
0
  TALLOC_CTX *frame;
6870
0
  struct tevent_context *ev;
6871
0
  struct tevent_req *req;
6872
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
6873
6874
0
  frame = talloc_stackframe();
6875
6876
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
6877
    /*
6878
     * Can't use sync call while an async call is in flight
6879
     */
6880
0
    status = NT_STATUS_INVALID_PARAMETER;
6881
0
    goto fail;
6882
0
  }
6883
0
  ev = samba_tevent_context_init(frame);
6884
0
  if (ev == NULL) {
6885
0
    goto fail;
6886
0
  }
6887
0
  req = cli_notify_send(ev, ev, cli, fnum, buffer_size,
6888
0
            completion_filter, recursive);
6889
0
  if (req == NULL) {
6890
0
    goto fail;
6891
0
  }
6892
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
6893
0
    goto fail;
6894
0
  }
6895
0
  status = cli_notify_recv(req, mem_ctx, pnum_changes, pchanges);
6896
0
 fail:
6897
0
  TALLOC_FREE(frame);
6898
0
  return status;
6899
0
}
6900
6901
struct cli_qpathinfo_state {
6902
  uint8_t *param;
6903
  uint8_t *data;
6904
  uint16_t setup[1];
6905
  uint32_t min_rdata;
6906
  uint8_t *rdata;
6907
  uint32_t num_rdata;
6908
};
6909
6910
static void cli_qpathinfo_done(struct tevent_req *subreq);
6911
static void cli_qpathinfo_done2(struct tevent_req *subreq);
6912
6913
struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
6914
              struct tevent_context *ev,
6915
              struct cli_state *cli, const char *fname,
6916
              uint16_t level, uint32_t min_rdata,
6917
              uint32_t max_rdata)
6918
0
{
6919
0
  struct tevent_req *req, *subreq;
6920
0
  struct cli_qpathinfo_state *state;
6921
0
  uint16_t additional_flags2 = 0;
6922
0
  char *fname_cp = NULL;
6923
6924
0
  req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo_state);
6925
0
  if (req == NULL) {
6926
0
    return NULL;
6927
0
  }
6928
6929
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
6930
0
    uint16_t smb2_level = 0;
6931
6932
0
    switch (level) {
6933
0
    case SMB_QUERY_FILE_ALT_NAME_INFO:
6934
0
      smb2_level = FSCC_FILE_ALTERNATE_NAME_INFORMATION;
6935
0
      break;
6936
0
    default:
6937
0
      tevent_req_nterror(req, NT_STATUS_INVALID_LEVEL);
6938
0
      return tevent_req_post(req, ev);
6939
0
    }
6940
6941
0
    subreq = cli_smb2_qpathinfo_send(state,
6942
0
             ev,
6943
0
             cli,
6944
0
             fname,
6945
0
             smb2_level,
6946
0
             min_rdata,
6947
0
             max_rdata);
6948
0
    if (tevent_req_nomem(subreq, req)) {
6949
0
      return tevent_req_post(req, ev);
6950
0
    }
6951
0
    tevent_req_set_callback(subreq, cli_qpathinfo_done2, req);
6952
0
    return req;
6953
0
  }
6954
6955
0
  state->min_rdata = min_rdata;
6956
0
  SSVAL(state->setup, 0, TRANSACT2_QPATHINFO);
6957
6958
0
  state->param = talloc_zero_array(state, uint8_t, 6);
6959
0
  if (tevent_req_nomem(state->param, req)) {
6960
0
    return tevent_req_post(req, ev);
6961
0
  }
6962
0
  SSVAL(state->param, 0, level);
6963
  /*
6964
   * qpathinfo on a DFS share must use DFS names.
6965
   */
6966
0
  fname_cp = smb1_dfs_share_path(state, cli, fname);
6967
0
  if (tevent_req_nomem(fname_cp, req)) {
6968
0
    return tevent_req_post(req, ev);
6969
0
  }
6970
0
  state->param = trans2_bytes_push_str(state->param,
6971
0
               smbXcli_conn_use_unicode(cli->conn),
6972
0
               fname_cp,
6973
0
               strlen(fname_cp)+1,
6974
0
               NULL);
6975
0
  if (tevent_req_nomem(state->param, req)) {
6976
0
    return tevent_req_post(req, ev);
6977
0
  }
6978
6979
0
  if (clistr_is_previous_version_path(fname) &&
6980
0
      !INFO_LEVEL_IS_UNIX(level)) {
6981
0
    additional_flags2 = FLAGS2_REPARSE_PATH;
6982
0
  }
6983
6984
0
  subreq = cli_trans_send(
6985
0
    state,      /* mem ctx. */
6986
0
    ev,     /* event ctx. */
6987
0
    cli,      /* cli_state. */
6988
0
    additional_flags2,  /* additional_flags2 */
6989
0
    SMBtrans2,   /* cmd. */
6990
0
    NULL,     /* pipe name. */
6991
0
    -1,     /* fid. */
6992
0
    0,      /* function. */
6993
0
    0,      /* flags. */
6994
0
    state->setup,   /* setup. */
6995
0
    1,      /* num setup uint16_t words. */
6996
0
    0,      /* max returned setup. */
6997
0
    state->param,   /* param. */
6998
0
    talloc_get_size(state->param),  /* num param. */
6999
0
    2,      /* max returned param. */
7000
0
    NULL,     /* data. */
7001
0
    0,      /* num data. */
7002
0
    max_rdata);   /* max returned data. */
7003
7004
0
  if (tevent_req_nomem(subreq, req)) {
7005
0
    return tevent_req_post(req, ev);
7006
0
  }
7007
0
  tevent_req_set_callback(subreq, cli_qpathinfo_done, req);
7008
0
  return req;
7009
0
}
7010
7011
static void cli_qpathinfo_done(struct tevent_req *subreq)
7012
0
{
7013
0
  struct tevent_req *req = tevent_req_callback_data(
7014
0
    subreq, struct tevent_req);
7015
0
  struct cli_qpathinfo_state *state = tevent_req_data(
7016
0
    req, struct cli_qpathinfo_state);
7017
0
  NTSTATUS status;
7018
7019
0
  status = cli_trans_recv(subreq, state, NULL, NULL, 0, NULL,
7020
0
        NULL, 0, NULL,
7021
0
        &state->rdata, state->min_rdata,
7022
0
        &state->num_rdata);
7023
0
  if (tevent_req_nterror(req, status)) {
7024
0
    return;
7025
0
  }
7026
0
  tevent_req_done(req);
7027
0
}
7028
7029
static void cli_qpathinfo_done2(struct tevent_req *subreq)
7030
0
{
7031
0
  struct tevent_req *req =
7032
0
    tevent_req_callback_data(subreq, struct tevent_req);
7033
0
  struct cli_qpathinfo_state *state =
7034
0
    tevent_req_data(req, struct cli_qpathinfo_state);
7035
0
  NTSTATUS status;
7036
7037
0
  status = cli_smb2_qpathinfo_recv(subreq,
7038
0
           state,
7039
0
           &state->rdata,
7040
0
           &state->num_rdata);
7041
0
  if (tevent_req_nterror(req, status)) {
7042
0
    return;
7043
0
  }
7044
0
  tevent_req_done(req);
7045
0
}
7046
7047
NTSTATUS cli_qpathinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7048
          uint8_t **rdata, uint32_t *num_rdata)
7049
0
{
7050
0
  struct cli_qpathinfo_state *state = tevent_req_data(
7051
0
    req, struct cli_qpathinfo_state);
7052
0
  NTSTATUS status;
7053
7054
0
  if (tevent_req_is_nterror(req, &status)) {
7055
0
    return status;
7056
0
  }
7057
0
  if (rdata != NULL) {
7058
0
    *rdata = talloc_move(mem_ctx, &state->rdata);
7059
0
  } else {
7060
0
    TALLOC_FREE(state->rdata);
7061
0
  }
7062
0
  if (num_rdata != NULL) {
7063
0
    *num_rdata = state->num_rdata;
7064
0
  }
7065
0
  return NT_STATUS_OK;
7066
0
}
7067
7068
NTSTATUS cli_qpathinfo(TALLOC_CTX *mem_ctx, struct cli_state *cli,
7069
           const char *fname, uint16_t level, uint32_t min_rdata,
7070
           uint32_t max_rdata,
7071
           uint8_t **rdata, uint32_t *num_rdata)
7072
0
{
7073
0
  TALLOC_CTX *frame = talloc_stackframe();
7074
0
  struct tevent_context *ev;
7075
0
  struct tevent_req *req;
7076
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
7077
7078
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
7079
    /*
7080
     * Can't use sync call while an async call is in flight
7081
     */
7082
0
    status = NT_STATUS_INVALID_PARAMETER;
7083
0
    goto fail;
7084
0
  }
7085
0
  ev = samba_tevent_context_init(frame);
7086
0
  if (ev == NULL) {
7087
0
    goto fail;
7088
0
  }
7089
0
  req = cli_qpathinfo_send(frame, ev, cli, fname, level, min_rdata,
7090
0
         max_rdata);
7091
0
  if (req == NULL) {
7092
0
    goto fail;
7093
0
  }
7094
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7095
0
    goto fail;
7096
0
  }
7097
0
  status = cli_qpathinfo_recv(req, mem_ctx, rdata, num_rdata);
7098
0
 fail:
7099
0
  TALLOC_FREE(frame);
7100
0
  return status;
7101
0
}
7102
7103
struct cli_qfileinfo_state {
7104
  uint16_t setup[1];
7105
  uint8_t param[4];
7106
  uint8_t *data;
7107
  uint16_t recv_flags2;
7108
  uint32_t min_rdata;
7109
  uint8_t *rdata;
7110
  uint32_t num_rdata;
7111
};
7112
7113
static void cli_qfileinfo_done2(struct tevent_req *subreq);
7114
static void cli_qfileinfo_done(struct tevent_req *subreq);
7115
7116
struct tevent_req *cli_qfileinfo_send(TALLOC_CTX *mem_ctx,
7117
              struct tevent_context *ev,
7118
              struct cli_state *cli,
7119
              uint16_t fnum,
7120
              uint16_t fscc_level,
7121
              uint32_t min_rdata,
7122
              uint32_t max_rdata)
7123
0
{
7124
0
  struct tevent_req *req, *subreq;
7125
0
  struct cli_qfileinfo_state *state;
7126
0
  uint16_t smb_level;
7127
7128
0
  req = tevent_req_create(mem_ctx, &state, struct cli_qfileinfo_state);
7129
0
  if (req == NULL) {
7130
0
    return NULL;
7131
0
  }
7132
7133
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7134
0
    max_rdata = MIN(max_rdata,
7135
0
        smb2cli_conn_max_trans_size(cli->conn));
7136
7137
0
    subreq = cli_smb2_query_info_fnum_send(
7138
0
      state,      /* mem_ctx */
7139
0
      ev,     /* ev */
7140
0
      cli,      /* cli */
7141
0
      fnum,     /* fnum */
7142
0
      SMB2_0_INFO_FILE, /* in_info_type */
7143
0
      fscc_level,   /* in_file_info_class */
7144
0
      max_rdata,    /* in_max_output_length */
7145
0
      NULL,     /* in_input_buffer */
7146
0
      0,      /* in_additional_info */
7147
0
      0);     /* in_flags */
7148
0
    if (tevent_req_nomem(subreq, req)) {
7149
0
      return tevent_req_post(req, ev);
7150
0
    }
7151
0
    tevent_req_set_callback(subreq, cli_qfileinfo_done2, req);
7152
0
    return req;
7153
0
  }
7154
7155
0
  max_rdata = MIN(max_rdata, UINT16_MAX);
7156
7157
0
  switch (fscc_level) {
7158
0
  case FSCC_FILE_BASIC_INFORMATION:
7159
0
    smb_level = SMB_QUERY_FILE_BASIC_INFO;
7160
0
    break;
7161
0
  case FSCC_FILE_STANDARD_INFORMATION:
7162
0
    smb_level = SMB_QUERY_FILE_STANDARD_INFO;
7163
0
    break;
7164
0
  case FSCC_FILE_EA_INFORMATION:
7165
0
    smb_level = SMB_QUERY_FILE_EA_INFO;
7166
0
    break;
7167
0
  case FSCC_FILE_NAME_INFORMATION:
7168
0
    smb_level = SMB_QUERY_FILE_NAME_INFO;
7169
0
    break;
7170
0
  case FSCC_FILE_ALL_INFORMATION:
7171
0
    smb_level = SMB_QUERY_FILE_ALL_INFO;
7172
0
    break;
7173
0
  case FSCC_FILE_ALTERNATE_NAME_INFORMATION:
7174
0
    smb_level = SMB_QUERY_FILE_ALT_NAME_INFO;
7175
0
    break;
7176
0
  case FSCC_FILE_STREAM_INFORMATION:
7177
0
    smb_level = SMB_QUERY_FILE_STREAM_INFO;
7178
0
    break;
7179
0
  case FSCC_FILE_COMPRESSION_INFORMATION:
7180
0
    smb_level = SMB_QUERY_COMPRESSION_INFO;
7181
0
    break;
7182
0
  default:
7183
    /* Probably wrong, but the server will tell us */
7184
0
    smb_level = fscc_level;
7185
0
    break;
7186
0
  }
7187
7188
0
  state->min_rdata = min_rdata;
7189
0
  SSVAL(state->param, 0, fnum);
7190
0
  SSVAL(state->param, 2, smb_level);
7191
0
  SSVAL(state->setup, 0, TRANSACT2_QFILEINFO);
7192
7193
0
  subreq = cli_trans_send(
7194
0
    state,      /* mem ctx. */
7195
0
    ev,     /* event ctx. */
7196
0
    cli,      /* cli_state. */
7197
0
    0,      /* additional_flags2 */
7198
0
    SMBtrans2,   /* cmd. */
7199
0
    NULL,     /* pipe name. */
7200
0
    -1,     /* fid. */
7201
0
    0,      /* function. */
7202
0
    0,      /* flags. */
7203
0
    state->setup,   /* setup. */
7204
0
    1,      /* num setup uint16_t words. */
7205
0
    0,      /* max returned setup. */
7206
0
    state->param,   /* param. */
7207
0
    sizeof(state->param), /* num param. */
7208
0
    2,      /* max returned param. */
7209
0
    NULL,     /* data. */
7210
0
    0,      /* num data. */
7211
0
    max_rdata);   /* max returned data. */
7212
7213
0
  if (tevent_req_nomem(subreq, req)) {
7214
0
    return tevent_req_post(req, ev);
7215
0
  }
7216
0
  tevent_req_set_callback(subreq, cli_qfileinfo_done, req);
7217
0
  return req;
7218
0
}
7219
7220
static void cli_qfileinfo_done2(struct tevent_req *subreq)
7221
0
{
7222
0
  struct tevent_req *req = tevent_req_callback_data(subreq,
7223
0
                struct tevent_req);
7224
0
  struct cli_qfileinfo_state *state = tevent_req_data(
7225
0
    req, struct cli_qfileinfo_state);
7226
0
  DATA_BLOB outbuf = {};
7227
0
  NTSTATUS status;
7228
7229
0
  status = cli_smb2_query_info_fnum_recv(subreq, state, &outbuf);
7230
0
  TALLOC_FREE(subreq);
7231
0
  if (tevent_req_nterror(req, status)) {
7232
0
    return;
7233
0
  }
7234
7235
0
  if (outbuf.length < state->min_rdata) {
7236
0
    tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
7237
0
    return;
7238
0
  }
7239
7240
0
  state->rdata = outbuf.data;
7241
0
  state->num_rdata = outbuf.length;
7242
0
  tevent_req_done(req);
7243
0
}
7244
7245
static void cli_qfileinfo_done(struct tevent_req *subreq)
7246
0
{
7247
0
  struct tevent_req *req = tevent_req_callback_data(
7248
0
    subreq, struct tevent_req);
7249
0
  struct cli_qfileinfo_state *state = tevent_req_data(
7250
0
    req, struct cli_qfileinfo_state);
7251
0
  NTSTATUS status;
7252
7253
0
  status = cli_trans_recv(subreq, state,
7254
0
        &state->recv_flags2,
7255
0
        NULL, 0, NULL,
7256
0
        NULL, 0, NULL,
7257
0
        &state->rdata, state->min_rdata,
7258
0
        &state->num_rdata);
7259
0
  if (tevent_req_nterror(req, status)) {
7260
0
    return;
7261
0
  }
7262
0
  tevent_req_done(req);
7263
0
}
7264
7265
NTSTATUS cli_qfileinfo_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7266
          uint16_t *recv_flags2,
7267
          uint8_t **rdata, uint32_t *num_rdata)
7268
0
{
7269
0
  struct cli_qfileinfo_state *state = tevent_req_data(
7270
0
    req, struct cli_qfileinfo_state);
7271
0
  NTSTATUS status;
7272
7273
0
  if (tevent_req_is_nterror(req, &status)) {
7274
0
    return status;
7275
0
  }
7276
7277
0
  if (recv_flags2 != NULL) {
7278
0
    *recv_flags2 = state->recv_flags2;
7279
0
  }
7280
0
  if (rdata != NULL) {
7281
0
    *rdata = talloc_move(mem_ctx, &state->rdata);
7282
0
  }
7283
0
  if (num_rdata != NULL) {
7284
0
    *num_rdata = state->num_rdata;
7285
0
  }
7286
7287
0
  tevent_req_received(req);
7288
0
  return NT_STATUS_OK;
7289
0
}
7290
7291
NTSTATUS cli_qfileinfo(TALLOC_CTX *mem_ctx,
7292
           struct cli_state *cli,
7293
           uint16_t fnum,
7294
           uint16_t fscc_level,
7295
           uint32_t min_rdata,
7296
           uint32_t max_rdata,
7297
           uint16_t *recv_flags2,
7298
           uint8_t **rdata,
7299
           uint32_t *num_rdata)
7300
0
{
7301
0
  TALLOC_CTX *frame = talloc_stackframe();
7302
0
  struct tevent_context *ev;
7303
0
  struct tevent_req *req;
7304
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
7305
7306
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
7307
    /*
7308
     * Can't use sync call while an async call is in flight
7309
     */
7310
0
    status = NT_STATUS_INVALID_PARAMETER;
7311
0
    goto fail;
7312
0
  }
7313
0
  ev = samba_tevent_context_init(frame);
7314
0
  if (ev == NULL) {
7315
0
    goto fail;
7316
0
  }
7317
0
  req = cli_qfileinfo_send(
7318
0
    frame, ev, cli, fnum, fscc_level, min_rdata, max_rdata);
7319
0
  if (req == NULL) {
7320
0
    goto fail;
7321
0
  }
7322
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7323
0
    goto fail;
7324
0
  }
7325
0
  status = cli_qfileinfo_recv(req, mem_ctx, recv_flags2, rdata, num_rdata);
7326
0
 fail:
7327
0
  TALLOC_FREE(frame);
7328
0
  return status;
7329
0
}
7330
7331
struct cli_flush_state {
7332
  uint16_t vwv[1];
7333
};
7334
7335
static void cli_flush_done(struct tevent_req *subreq);
7336
7337
struct tevent_req *cli_flush_send(TALLOC_CTX *mem_ctx,
7338
          struct tevent_context *ev,
7339
          struct cli_state *cli,
7340
          uint16_t fnum)
7341
0
{
7342
0
  struct tevent_req *req, *subreq;
7343
0
  struct cli_flush_state *state;
7344
7345
0
  req = tevent_req_create(mem_ctx, &state, struct cli_flush_state);
7346
0
  if (req == NULL) {
7347
0
    return NULL;
7348
0
  }
7349
0
  SSVAL(state->vwv + 0, 0, fnum);
7350
7351
0
  subreq = cli_smb_send(state, ev, cli, SMBflush, 0, 0, 1, state->vwv,
7352
0
            0, NULL);
7353
0
  if (tevent_req_nomem(subreq, req)) {
7354
0
    return tevent_req_post(req, ev);
7355
0
  }
7356
0
  tevent_req_set_callback(subreq, cli_flush_done, req);
7357
0
  return req;
7358
0
}
7359
7360
static void cli_flush_done(struct tevent_req *subreq)
7361
0
{
7362
0
  struct tevent_req *req = tevent_req_callback_data(
7363
0
    subreq, struct tevent_req);
7364
0
  NTSTATUS status;
7365
7366
0
  status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
7367
0
  TALLOC_FREE(subreq);
7368
0
  if (tevent_req_nterror(req, status)) {
7369
0
    return;
7370
0
  }
7371
0
  tevent_req_done(req);
7372
0
}
7373
7374
NTSTATUS cli_flush_recv(struct tevent_req *req)
7375
0
{
7376
0
  return tevent_req_simple_recv_ntstatus(req);
7377
0
}
7378
7379
NTSTATUS cli_flush(TALLOC_CTX *mem_ctx, struct cli_state *cli, uint16_t fnum)
7380
0
{
7381
0
  TALLOC_CTX *frame = talloc_stackframe();
7382
0
  struct tevent_context *ev;
7383
0
  struct tevent_req *req;
7384
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
7385
7386
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
7387
    /*
7388
     * Can't use sync call while an async call is in flight
7389
     */
7390
0
    status = NT_STATUS_INVALID_PARAMETER;
7391
0
    goto fail;
7392
0
  }
7393
0
  ev = samba_tevent_context_init(frame);
7394
0
  if (ev == NULL) {
7395
0
    goto fail;
7396
0
  }
7397
0
  req = cli_flush_send(frame, ev, cli, fnum);
7398
0
  if (req == NULL) {
7399
0
    goto fail;
7400
0
  }
7401
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7402
0
    goto fail;
7403
0
  }
7404
0
  status = cli_flush_recv(req);
7405
0
 fail:
7406
0
  TALLOC_FREE(frame);
7407
0
  return status;
7408
0
}
7409
7410
struct cli_shadow_copy_data_state {
7411
  uint16_t setup[4];
7412
  uint8_t *data;
7413
  uint32_t num_data;
7414
  bool get_names;
7415
};
7416
7417
static void cli_shadow_copy_data_done(struct tevent_req *subreq);
7418
7419
struct tevent_req *cli_shadow_copy_data_send(TALLOC_CTX *mem_ctx,
7420
               struct tevent_context *ev,
7421
               struct cli_state *cli,
7422
               uint16_t fnum,
7423
               bool get_names)
7424
0
{
7425
0
  struct tevent_req *req, *subreq;
7426
0
  struct cli_shadow_copy_data_state *state;
7427
0
  uint32_t ret_size;
7428
7429
0
  req = tevent_req_create(mem_ctx, &state,
7430
0
        struct cli_shadow_copy_data_state);
7431
0
  if (req == NULL) {
7432
0
    return NULL;
7433
0
  }
7434
0
  state->get_names = get_names;
7435
0
  ret_size = get_names ? CLI_BUFFER_SIZE : 16;
7436
7437
0
  SIVAL(state->setup + 0, 0, FSCTL_GET_SHADOW_COPY_DATA);
7438
0
  SSVAL(state->setup + 2, 0, fnum);
7439
0
  SCVAL(state->setup + 3, 0, 1); /* isFsctl */
7440
0
  SCVAL(state->setup + 3, 1, 0); /* compfilter, isFlags (WSSP) */
7441
7442
0
  subreq = cli_trans_send(
7443
0
    state, ev, cli, 0, SMBnttrans, NULL, 0, NT_TRANSACT_IOCTL, 0,
7444
0
    state->setup, ARRAY_SIZE(state->setup),
7445
0
    ARRAY_SIZE(state->setup),
7446
0
    NULL, 0, 0,
7447
0
    NULL, 0, ret_size);
7448
0
  if (tevent_req_nomem(subreq, req)) {
7449
0
    return tevent_req_post(req, ev);
7450
0
  }
7451
0
  tevent_req_set_callback(subreq, cli_shadow_copy_data_done, req);
7452
0
  return req;
7453
0
}
7454
7455
static void cli_shadow_copy_data_done(struct tevent_req *subreq)
7456
0
{
7457
0
  struct tevent_req *req = tevent_req_callback_data(
7458
0
    subreq, struct tevent_req);
7459
0
  struct cli_shadow_copy_data_state *state = tevent_req_data(
7460
0
    req, struct cli_shadow_copy_data_state);
7461
0
  NTSTATUS status;
7462
7463
0
  status = cli_trans_recv(subreq, state, NULL,
7464
0
        NULL, 0, NULL, /* setup */
7465
0
        NULL, 0, NULL, /* param */
7466
0
        &state->data, 12, &state->num_data);
7467
0
  TALLOC_FREE(subreq);
7468
0
  if (tevent_req_nterror(req, status)) {
7469
0
    return;
7470
0
  }
7471
0
  tevent_req_done(req);
7472
0
}
7473
7474
NTSTATUS cli_shadow_copy_data_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
7475
           char ***pnames, int *pnum_names)
7476
0
{
7477
0
  struct cli_shadow_copy_data_state *state = tevent_req_data(
7478
0
    req, struct cli_shadow_copy_data_state);
7479
0
  char **names = NULL;
7480
0
  uint32_t i, num_names;
7481
0
  uint32_t dlength;
7482
0
  uint8_t *endp = NULL;
7483
0
  NTSTATUS status;
7484
7485
0
  if (tevent_req_is_nterror(req, &status)) {
7486
0
    return status;
7487
0
  }
7488
7489
0
  if (state->num_data < 16) {
7490
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
7491
0
  }
7492
7493
0
  num_names = IVAL(state->data, 4);
7494
0
  dlength = IVAL(state->data, 8);
7495
7496
0
  if (num_names > 0x7FFFFFFF) {
7497
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
7498
0
  }
7499
7500
0
  if (!state->get_names) {
7501
0
    *pnum_names = (int)num_names;
7502
0
    return NT_STATUS_OK;
7503
0
  }
7504
7505
0
  if (dlength + 12 < 12) {
7506
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
7507
0
  }
7508
0
  if (dlength + 12 > state->num_data) {
7509
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
7510
0
  }
7511
0
  if (state->num_data + (2 * sizeof(SHADOW_COPY_LABEL)) <
7512
0
      state->num_data) {
7513
0
    return NT_STATUS_INVALID_NETWORK_RESPONSE;
7514
0
  }
7515
7516
0
  names = talloc_array(mem_ctx, char *, num_names);
7517
0
  if (names == NULL) {
7518
0
    return NT_STATUS_NO_MEMORY;
7519
0
  }
7520
7521
0
  endp = state->data + state->num_data;
7522
7523
0
  for (i=0; i<num_names; i++) {
7524
0
    bool ret;
7525
0
    uint8_t *src;
7526
0
    size_t converted_size;
7527
7528
0
    src = state->data + 12 + i * 2 * sizeof(SHADOW_COPY_LABEL);
7529
7530
0
    if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
7531
0
      return NT_STATUS_INVALID_NETWORK_RESPONSE;
7532
0
    }
7533
7534
0
    ret = convert_string_talloc(
7535
0
      names, CH_UTF16LE, CH_UNIX,
7536
0
      src, 2 * sizeof(SHADOW_COPY_LABEL),
7537
0
      &names[i], &converted_size);
7538
0
    if (!ret) {
7539
0
      TALLOC_FREE(names);
7540
0
      return NT_STATUS_INVALID_NETWORK_RESPONSE;
7541
0
    }
7542
0
  }
7543
0
  *pnum_names = (int)num_names;
7544
0
  *pnames = names;
7545
0
  return NT_STATUS_OK;
7546
0
}
7547
7548
NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
7549
            uint16_t fnum, bool get_names,
7550
            char ***pnames, int *pnum_names)
7551
0
{
7552
0
  TALLOC_CTX *frame = NULL;
7553
0
  struct tevent_context *ev;
7554
0
  struct tevent_req *req;
7555
0
  NTSTATUS status = NT_STATUS_NO_MEMORY;
7556
7557
0
        if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7558
0
    return cli_smb2_shadow_copy_data(mem_ctx,
7559
0
          cli,
7560
0
          fnum,
7561
0
          get_names,
7562
0
          pnames,
7563
0
          pnum_names);
7564
0
  }
7565
7566
0
  frame = talloc_stackframe();
7567
7568
0
  if (smbXcli_conn_has_async_calls(cli->conn)) {
7569
    /*
7570
     * Can't use sync call while an async call is in flight
7571
     */
7572
0
    status = NT_STATUS_INVALID_PARAMETER;
7573
0
    goto fail;
7574
0
  }
7575
0
  ev = samba_tevent_context_init(frame);
7576
0
  if (ev == NULL) {
7577
0
    goto fail;
7578
0
  }
7579
0
  req = cli_shadow_copy_data_send(frame, ev, cli, fnum, get_names);
7580
0
  if (req == NULL) {
7581
0
    goto fail;
7582
0
  }
7583
0
  if (!tevent_req_poll_ntstatus(req, ev, &status)) {
7584
0
    goto fail;
7585
0
  }
7586
0
  status = cli_shadow_copy_data_recv(req, mem_ctx, pnames, pnum_names);
7587
0
 fail:
7588
0
  TALLOC_FREE(frame);
7589
0
  return status;
7590
0
}
7591
7592
struct cli_fsctl_state {
7593
  DATA_BLOB out;
7594
};
7595
7596
static void cli_fsctl_smb1_done(struct tevent_req *subreq);
7597
static void cli_fsctl_smb2_done(struct tevent_req *subreq);
7598
7599
struct tevent_req *cli_fsctl_send(
7600
  TALLOC_CTX *mem_ctx,
7601
  struct tevent_context *ev,
7602
  struct cli_state *cli,
7603
  uint16_t fnum,
7604
  uint32_t ctl_code,
7605
  const DATA_BLOB *in,
7606
  uint32_t max_out)
7607
0
{
7608
0
  struct tevent_req *req = NULL, *subreq = NULL;
7609
0
  struct cli_fsctl_state *state = NULL;
7610
0
  uint16_t *setup = NULL;
7611
0
  uint8_t *data = NULL;
7612
0
  uint32_t num_data = 0;
7613
7614
0
  req = tevent_req_create(mem_ctx, &state, struct cli_fsctl_state);
7615
0
  if (req == NULL) {
7616
0
    return NULL;
7617
0
  }
7618
7619
0
  if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
7620
0
    subreq = cli_smb2_fsctl_send(
7621
0
      state, ev, cli, fnum, ctl_code, in, max_out);
7622
0
    if (tevent_req_nomem(subreq, req)) {
7623
0
      return tevent_req_post(req, ev);
7624
0
    }
7625
0
    tevent_req_set_callback(subreq, cli_fsctl_smb2_done, req);
7626
0
    return req;
7627
0
  }
7628
7629
0
  setup = talloc_array(state, uint16_t, 4);
7630
0
  if (tevent_req_nomem(setup, req)) {
7631
0
    return tevent_req_post(req, ev);
7632
0
  }
7633
0
  SIVAL(setup, 0, ctl_code);
7634
0
  SSVAL(setup, 4, fnum);
7635
0
  SCVAL(setup, 6, 1);  /* IsFcntl */
7636
0
  SCVAL(setup, 7, 0);  /* IsFlags */
7637
7638
0
  if (in) {
7639
0
    data = in->data;
7640
0
    num_data = in->length;
7641
0
  }
7642
7643
0
  subreq = cli_trans_send(state,
7644
0
        ev,
7645
0
        cli,
7646
0
        0,       /* additional_flags2 */
7647
0
        SMBnttrans,    /* cmd */
7648
0
        NULL,      /* name */
7649
0
        -1,      /* fid */
7650
0
        NT_TRANSACT_IOCTL, /* function */
7651
0
        0,       /* flags */
7652
0
        setup,
7653
0
        4,
7654
0
        0, /* setup */
7655
0
        NULL,
7656
0
        0,
7657
0
        0, /* param */
7658
0
        data,
7659
0
        num_data,
7660
0
        max_out); /* data */
7661
7662
0
  if (tevent_req_nomem(subreq, req)) {
7663
0
    return tevent_req_post(req, ev);
7664
0
  }
7665
0
  tevent_req_set_callback(subreq, cli_fsctl_smb1_done, req);
7666
0
  return req;
7667
0
}
7668
7669
static void cli_fsctl_smb2_done(struct tevent_req *subreq)
7670
0
{
7671
0
  struct tevent_req *req = tevent_req_callback_data(
7672
0
    subreq, struct tevent_req);
7673
0
  struct cli_fsctl_state *state = tevent_req_data(
7674
0
    req, struct cli_fsctl_state);
7675
0
  NTSTATUS status;
7676
7677
0
  status = cli_smb2_fsctl_recv(subreq, state, &state->out);
7678
0
  tevent_req_simple_finish_ntstatus(subreq, status);
7679
0
}
7680
7681
static void cli_fsctl_smb1_done(struct tevent_req *subreq)
7682
0
{
7683
0
  struct tevent_req *req = tevent_req_callback_data(
7684
0
    subreq, struct tevent_req);
7685
0
  struct cli_fsctl_state *state = tevent_req_data(
7686
0
    req, struct cli_fsctl_state);
7687
0
  uint8_t *out = NULL;
7688
0
  uint32_t out_len;
7689
0
  NTSTATUS status;
7690
7691
0
  status = cli_trans_recv(
7692
0
    subreq, state, NULL,
7693
0
    NULL, 0, NULL, /* rsetup */
7694
0
    NULL, 0, NULL, /* rparam */
7695
0
    &out, 0, &out_len);
7696
0
  TALLOC_FREE(subreq);
7697
0
  if (tevent_req_nterror(req, status)) {
7698
0
    return;
7699
0
  }
7700
0
  state->out = (DATA_BLOB) {
7701
0
    .data = out, .length = out_len,
7702
0
  };
7703
0
  tevent_req_done(req);
7704
0
}
7705
7706
NTSTATUS cli_fsctl_recv(
7707
  struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
7708
0
{
7709
0
  struct cli_fsctl_state *state = tevent_req_data(
7710
0
    req, struct cli_fsctl_state);
7711
0
  NTSTATUS status;
7712
7713
0
  if (tevent_req_is_nterror(req, &status)) {
7714
0
    return status;
7715
0
  }
7716
7717
0
  if (out != NULL) {
7718
0
    *out = (DATA_BLOB) {
7719
0
      .data = talloc_move(mem_ctx, &state->out.data),
7720
0
      .length = state->out.length,
7721
0
    };
7722
0
  }
7723
7724
0
  return NT_STATUS_OK;
7725
0
}