LCOV - code coverage report
Current view: top level - source3/libsmb - cli_smb2_fnum.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 1384 2188 63.3 %
Date: 2024-05-31 13:13:24 Functions: 97 116 83.6 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    smb2 lib
       4             :    Copyright (C) Jeremy Allison 2013
       5             :    Copyright (C) Volker Lendecke 2013
       6             :    Copyright (C) Stefan Metzmacher 2013
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : /*
      23             :  This code is a thin wrapper around the existing
      24             :  cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c,
      25             :  but allows the handles to be mapped to uint16_t fnums,
      26             :  which are easier for smbclient to use.
      27             : */
      28             : 
      29             : #include "includes.h"
      30             : #include "client.h"
      31             : #include "async_smb.h"
      32             : #include "../libcli/smb/smbXcli_base.h"
      33             : #include "cli_smb2_fnum.h"
      34             : #include "trans2.h"
      35             : #include "clirap.h"
      36             : #include "../libcli/smb/smb2_create_blob.h"
      37             : #include "libsmb/proto.h"
      38             : #include "lib/util/tevent_ntstatus.h"
      39             : #include "../libcli/security/security.h"
      40             : #include "../librpc/gen_ndr/ndr_security.h"
      41             : #include "lib/util_ea.h"
      42             : #include "librpc/gen_ndr/ndr_ioctl.h"
      43             : #include "ntioctl.h"
      44             : #include "librpc/gen_ndr/ndr_quota.h"
      45             : #include "librpc/gen_ndr/ndr_smb3posix.h"
      46             : #include "lib/util/string_wrappers.h"
      47             : #include "lib/util/idtree.h"
      48             : 
      49             : struct smb2_hnd {
      50             :         uint64_t fid_persistent;
      51             :         uint64_t fid_volatile;
      52             : };
      53             : 
      54             : /*
      55             :  * Handle mapping code.
      56             :  */
      57             : 
      58             : /***************************************************************
      59             :  Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd.
      60             :  Ensures handle is owned by cli struct.
      61             : ***************************************************************/
      62             : 
      63       47494 : static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli,
      64             :                                 const struct smb2_hnd *ph,      /* In */
      65             :                                 uint16_t *pfnum)                /* Out */
      66             : {
      67           0 :         int ret;
      68       47494 :         struct idr_context *idp = cli->smb2.open_handles;
      69       47494 :         struct smb2_hnd *owned_h = talloc_memdup(cli,
      70             :                                                 ph,
      71             :                                                 sizeof(struct smb2_hnd));
      72             : 
      73       47494 :         if (owned_h == NULL) {
      74           0 :                 return NT_STATUS_NO_MEMORY;
      75             :         }
      76             : 
      77       47494 :         if (idp == NULL) {
      78             :                 /* Lazy init */
      79        9345 :                 cli->smb2.open_handles = idr_init(cli);
      80        9345 :                 if (cli->smb2.open_handles == NULL) {
      81           0 :                         TALLOC_FREE(owned_h);
      82           0 :                         return NT_STATUS_NO_MEMORY;
      83             :                 }
      84        9345 :                 idp = cli->smb2.open_handles;
      85             :         }
      86             : 
      87       47494 :         ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE);
      88       47494 :         if (ret == -1) {
      89           0 :                 TALLOC_FREE(owned_h);
      90           0 :                 return NT_STATUS_NO_MEMORY;
      91             :         }
      92             : 
      93       47494 :         *pfnum = (uint16_t)ret;
      94       47494 :         return NT_STATUS_OK;
      95             : }
      96             : 
      97             : /***************************************************************
      98             :  Return the smb2_hnd pointer associated with the given fnum.
      99             : ***************************************************************/
     100             : 
     101       91273 : static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli,
     102             :                                 uint16_t fnum,          /* In */
     103             :                                 struct smb2_hnd **pph)  /* Out */
     104             : {
     105       91273 :         struct idr_context *idp = cli->smb2.open_handles;
     106             : 
     107       91273 :         if (idp == NULL) {
     108           0 :                 return NT_STATUS_INVALID_PARAMETER;
     109             :         }
     110       91273 :         *pph = (struct smb2_hnd *)idr_find(idp, fnum);
     111       91273 :         if (*pph == NULL) {
     112          12 :                 return NT_STATUS_INVALID_HANDLE;
     113             :         }
     114       91261 :         return NT_STATUS_OK;
     115             : }
     116             : 
     117             : /***************************************************************
     118             :  Delete the fnum to smb2_hnd mapping. Zeros out handle on
     119             :  successful return.
     120             : ***************************************************************/
     121             : 
     122       47468 : static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli,
     123             :                                 struct smb2_hnd **pph,  /* In */
     124             :                                 uint16_t fnum)                  /* In */
     125             : {
     126       47468 :         struct idr_context *idp = cli->smb2.open_handles;
     127           0 :         struct smb2_hnd *ph;
     128             : 
     129       47468 :         if (idp == NULL) {
     130           0 :                 return NT_STATUS_INVALID_PARAMETER;
     131             :         }
     132             : 
     133       47468 :         ph = (struct smb2_hnd *)idr_find(idp, fnum);
     134       47468 :         if (ph != *pph) {
     135           0 :                 return NT_STATUS_INVALID_PARAMETER;
     136             :         }
     137       47468 :         idr_remove(idp, fnum);
     138       47468 :         TALLOC_FREE(*pph);
     139       47468 :         return NT_STATUS_OK;
     140             : }
     141             : 
     142             : /***************************************************************
     143             :  Oplock mapping code.
     144             : ***************************************************************/
     145             : 
     146       57631 : static uint8_t flags_to_smb2_oplock(struct cli_smb2_create_flags create_flags)
     147             : {
     148       57631 :         if (create_flags.batch_oplock) {
     149          18 :                 return SMB2_OPLOCK_LEVEL_BATCH;
     150       57613 :         } else if (create_flags.exclusive_oplock) {
     151           0 :                 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
     152             :         }
     153             : 
     154             :         /* create_flags doesn't do a level2 request. */
     155       57613 :         return SMB2_OPLOCK_LEVEL_NONE;
     156             : }
     157             : 
     158             : /***************************************************************
     159             :  If we're on a DFS share, ensure we convert to a full DFS path
     160             :  if this hasn't already been done.
     161             : ***************************************************************/
     162             : 
     163       57631 : static char *smb2_dfs_share_path(TALLOC_CTX *ctx,
     164             :                                  struct cli_state *cli,
     165             :                                  char *path)
     166             : {
     167      112997 :         bool is_dfs = smbXcli_conn_dfs_supported(cli->conn) &&
     168       55366 :                         smbXcli_tcon_is_dfs_share(cli->smb2.tcon);
     169       57631 :         bool is_already_dfs_path = false;
     170             : 
     171       57631 :         if (!is_dfs) {
     172       44209 :                 return path;
     173             :         }
     174       13422 :         is_already_dfs_path = cli_dfs_is_already_full_path(cli, path);
     175       13422 :         if (is_already_dfs_path) {
     176       13372 :                 return path;
     177             :         }
     178          50 :         if (path[0] == '\0') {
     179           6 :                 return talloc_asprintf(ctx,
     180             :                                        "%s\\%s",
     181             :                                         smbXcli_conn_remote_name(cli->conn),
     182             :                                         cli->share);
     183             :         }
     184          76 :         while (*path == '\\') {
     185          32 :                 path++;
     186             :         }
     187          44 :         return talloc_asprintf(ctx,
     188             :                                "%s\\%s\\%s",
     189             :                                smbXcli_conn_remote_name(cli->conn),
     190             :                                cli->share,
     191             :                                path);
     192             : }
     193             : 
     194             : /***************************************************************
     195             :  Small wrapper that allows SMB2 create to return a uint16_t fnum.
     196             : ***************************************************************/
     197             : 
     198             : struct cli_smb2_create_fnum_state {
     199             :         struct cli_state *cli;
     200             :         struct smb2_create_blobs in_cblobs;
     201             :         struct smb2_create_blobs out_cblobs;
     202             :         struct smb_create_returns cr;
     203             :         struct symlink_reparse_struct *symlink;
     204             :         uint16_t fnum;
     205             :         struct tevent_req *subreq;
     206             : };
     207             : 
     208             : static void cli_smb2_create_fnum_done(struct tevent_req *subreq);
     209             : static bool cli_smb2_create_fnum_cancel(struct tevent_req *req);
     210             : 
     211       57631 : struct tevent_req *cli_smb2_create_fnum_send(
     212             :         TALLOC_CTX *mem_ctx,
     213             :         struct tevent_context *ev,
     214             :         struct cli_state *cli,
     215             :         const char *fname_in,
     216             :         struct cli_smb2_create_flags create_flags,
     217             :         uint32_t impersonation_level,
     218             :         uint32_t desired_access,
     219             :         uint32_t file_attributes,
     220             :         uint32_t share_access,
     221             :         uint32_t create_disposition,
     222             :         uint32_t create_options,
     223             :         const struct smb2_create_blobs *in_cblobs)
     224             : {
     225           0 :         struct tevent_req *req, *subreq;
     226           0 :         struct cli_smb2_create_fnum_state *state;
     227       57631 :         char *fname = NULL;
     228       57631 :         size_t fname_len = 0;
     229           0 :         bool have_twrp;
     230           0 :         NTTIME ntt;
     231           0 :         NTSTATUS status;
     232             : 
     233       57631 :         req = tevent_req_create(mem_ctx, &state,
     234             :                                 struct cli_smb2_create_fnum_state);
     235       57631 :         if (req == NULL) {
     236           0 :                 return NULL;
     237             :         }
     238       57631 :         state->cli = cli;
     239             : 
     240       57631 :         fname = talloc_strdup(state, fname_in);
     241       57631 :         if (tevent_req_nomem(fname, req)) {
     242           0 :                 return tevent_req_post(req, ev);
     243             :         }
     244             : 
     245       57631 :         if (cli->backup_intent) {
     246          28 :                 create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
     247             :         }
     248             : 
     249       57631 :         if (cli->smb2.client_smb311_posix) {
     250          12 :                 uint8_t modebuf[4] = {
     251             :                         0,
     252             :                 };
     253             : 
     254           0 :                 status =
     255          12 :                         smb2_create_blob_add(state,
     256          12 :                                              &state->in_cblobs,
     257             :                                              SMB2_CREATE_TAG_POSIX,
     258          12 :                                              (DATA_BLOB){
     259             :                                                      .data = modebuf,
     260             :                                                      .length = sizeof(modebuf),
     261             :                                              });
     262          12 :                 if (tevent_req_nterror(req, status)) {
     263           0 :                         return tevent_req_post(req, ev);
     264             :                 }
     265             :         }
     266             : 
     267             :         /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
     268       57631 :         have_twrp = clistr_smb2_extract_snapshot_token(fname, &ntt);
     269       57631 :         if (have_twrp) {
     270        2655 :                 status = smb2_create_blob_add(
     271             :                         state,
     272        2655 :                         &state->in_cblobs,
     273             :                         SMB2_CREATE_TAG_TWRP,
     274        2655 :                         (DATA_BLOB) {
     275             :                                 .data = (uint8_t *)&ntt,
     276             :                                 .length = sizeof(ntt),
     277             :                         });
     278        2655 :                 if (tevent_req_nterror(req, status)) {
     279           0 :                         return tevent_req_post(req, ev);
     280             :                 }
     281             :         }
     282             : 
     283       57631 :         if (in_cblobs != NULL) {
     284             :                 uint32_t i;
     285        4292 :                 for (i=0; i<in_cblobs->num_blobs; i++) {
     286        2146 :                         struct smb2_create_blob *b = &in_cblobs->blobs[i];
     287        2146 :                         status = smb2_create_blob_add(
     288        2146 :                                 state, &state->in_cblobs, b->tag, b->data);
     289        2146 :                         if (!NT_STATUS_IS_OK(status)) {
     290           0 :                                 tevent_req_nterror(req, status);
     291           0 :                                 return tevent_req_post(req, ev);
     292             :                         }
     293             :                 }
     294             :         }
     295             : 
     296       57631 :         fname = smb2_dfs_share_path(state, cli, fname);
     297       57631 :         if (tevent_req_nomem(fname, req)) {
     298           0 :                 return tevent_req_post(req, ev);
     299             :         }
     300       57631 :         fname_len = strlen(fname);
     301             : 
     302             :         /* SMB2 is pickier about pathnames. Ensure it doesn't
     303             :            start in a '\' */
     304       57631 :         if (*fname == '\\') {
     305       39911 :                 fname++;
     306       39911 :                 fname_len--;
     307             :         }
     308             : 
     309             :         /* Or end in a '\' */
     310       57631 :         if (fname_len > 0 && fname[fname_len-1] == '\\') {
     311        1340 :                 fname[fname_len-1] = '\0';
     312             :         }
     313             : 
     314      115262 :         subreq = smb2cli_create_send(state, ev,
     315             :                                      cli->conn,
     316       57631 :                                      cli->timeout,
     317             :                                      cli->smb2.session,
     318             :                                      cli->smb2.tcon,
     319             :                                      fname,
     320       57631 :                                      flags_to_smb2_oplock(create_flags),
     321             :                                      impersonation_level,
     322             :                                      desired_access,
     323             :                                      file_attributes,
     324             :                                      share_access,
     325             :                                      create_disposition,
     326             :                                      create_options,
     327       57631 :                                      &state->in_cblobs);
     328       57631 :         if (tevent_req_nomem(subreq, req)) {
     329           0 :                 return tevent_req_post(req, ev);
     330             :         }
     331       57631 :         tevent_req_set_callback(subreq, cli_smb2_create_fnum_done, req);
     332             : 
     333       57631 :         state->subreq = subreq;
     334       57631 :         tevent_req_set_cancel_fn(req, cli_smb2_create_fnum_cancel);
     335             : 
     336       57631 :         return req;
     337             : }
     338             : 
     339       57631 : static void cli_smb2_create_fnum_done(struct tevent_req *subreq)
     340             : {
     341       57631 :         struct tevent_req *req = tevent_req_callback_data(
     342             :                 subreq, struct tevent_req);
     343       57631 :         struct cli_smb2_create_fnum_state *state = tevent_req_data(
     344             :                 req, struct cli_smb2_create_fnum_state);
     345           0 :         struct smb2_hnd h;
     346           0 :         NTSTATUS status;
     347             : 
     348       57631 :         status = smb2cli_create_recv(
     349             :                 subreq,
     350             :                 &h.fid_persistent,
     351             :                 &h.fid_volatile, &state->cr,
     352             :                 state,
     353             :                 &state->out_cblobs,
     354             :                 &state->symlink);
     355       57631 :         TALLOC_FREE(subreq);
     356       57631 :         if (tevent_req_nterror(req, status)) {
     357       10137 :                 return;
     358             :         }
     359             : 
     360       47494 :         status = map_smb2_handle_to_fnum(state->cli, &h, &state->fnum);
     361       47494 :         if (tevent_req_nterror(req, status)) {
     362           0 :                 return;
     363             :         }
     364       47494 :         tevent_req_done(req);
     365             : }
     366             : 
     367           2 : static bool cli_smb2_create_fnum_cancel(struct tevent_req *req)
     368             : {
     369           2 :         struct cli_smb2_create_fnum_state *state = tevent_req_data(
     370             :                 req, struct cli_smb2_create_fnum_state);
     371           2 :         return tevent_req_cancel(state->subreq);
     372             : }
     373             : 
     374       57631 : NTSTATUS cli_smb2_create_fnum_recv(
     375             :         struct tevent_req *req,
     376             :         uint16_t *pfnum,
     377             :         struct smb_create_returns *cr,
     378             :         TALLOC_CTX *mem_ctx,
     379             :         struct smb2_create_blobs *out_cblobs,
     380             :         struct symlink_reparse_struct **symlink)
     381             : {
     382       57631 :         struct cli_smb2_create_fnum_state *state = tevent_req_data(
     383             :                 req, struct cli_smb2_create_fnum_state);
     384           0 :         NTSTATUS status;
     385             : 
     386       57631 :         if (tevent_req_is_nterror(req, &status)) {
     387       10137 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) &&
     388             :                     (symlink != NULL)) {
     389           0 :                         *symlink = talloc_move(mem_ctx, &state->symlink);
     390             :                 }
     391       10137 :                 state->cli->raw_status = status;
     392       10137 :                 return status;
     393             :         }
     394       47494 :         if (pfnum != NULL) {
     395       47494 :                 *pfnum = state->fnum;
     396             :         }
     397       47494 :         if (cr != NULL) {
     398       25079 :                 *cr = state->cr;
     399             :         }
     400       47494 :         if (out_cblobs != NULL) {
     401        2142 :                 *out_cblobs = (struct smb2_create_blobs) {
     402        2142 :                         .num_blobs = state->out_cblobs.num_blobs,
     403        2142 :                         .blobs = talloc_move(
     404             :                                 mem_ctx, &state->out_cblobs.blobs),
     405             :                 };
     406             :         }
     407       47494 :         state->cli->raw_status = NT_STATUS_OK;
     408       47494 :         return NT_STATUS_OK;
     409             : }
     410             : 
     411       11141 : NTSTATUS cli_smb2_create_fnum(
     412             :         struct cli_state *cli,
     413             :         const char *fname,
     414             :         struct cli_smb2_create_flags create_flags,
     415             :         uint32_t impersonation_level,
     416             :         uint32_t desired_access,
     417             :         uint32_t file_attributes,
     418             :         uint32_t share_access,
     419             :         uint32_t create_disposition,
     420             :         uint32_t create_options,
     421             :         const struct smb2_create_blobs *in_cblobs,
     422             :         uint16_t *pfid,
     423             :         struct smb_create_returns *cr,
     424             :         TALLOC_CTX *mem_ctx,
     425             :         struct smb2_create_blobs *out_cblobs)
     426             : {
     427       11141 :         TALLOC_CTX *frame = talloc_stackframe();
     428           0 :         struct tevent_context *ev;
     429           0 :         struct tevent_req *req;
     430       11141 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     431             : 
     432       11141 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     433             :                 /*
     434             :                  * Can't use sync call while an async call is in flight
     435             :                  */
     436           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     437           0 :                 goto fail;
     438             :         }
     439       11141 :         ev = samba_tevent_context_init(frame);
     440       11141 :         if (ev == NULL) {
     441           0 :                 goto fail;
     442             :         }
     443       11141 :         req = cli_smb2_create_fnum_send(
     444             :                 frame,
     445             :                 ev,
     446             :                 cli,
     447             :                 fname,
     448             :                 create_flags,
     449             :                 impersonation_level,
     450             :                 desired_access,
     451             :                 file_attributes,
     452             :                 share_access,
     453             :                 create_disposition,
     454             :                 create_options,
     455             :                 in_cblobs);
     456       11141 :         if (req == NULL) {
     457           0 :                 goto fail;
     458             :         }
     459       11141 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     460           0 :                 goto fail;
     461             :         }
     462       11141 :         status = cli_smb2_create_fnum_recv(
     463             :                 req, pfid, cr, mem_ctx, out_cblobs, NULL);
     464       11141 :  fail:
     465       11141 :         TALLOC_FREE(frame);
     466       11141 :         return status;
     467             : }
     468             : 
     469             : /***************************************************************
     470             :  Small wrapper that allows SMB2 close to use a uint16_t fnum.
     471             : ***************************************************************/
     472             : 
     473             : struct cli_smb2_close_fnum_state {
     474             :         struct cli_state *cli;
     475             :         uint16_t fnum;
     476             :         struct smb2_hnd *ph;
     477             : };
     478             : 
     479             : static void cli_smb2_close_fnum_done(struct tevent_req *subreq);
     480             : 
     481       47482 : struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
     482             :                                             struct tevent_context *ev,
     483             :                                             struct cli_state *cli,
     484             :                                             uint16_t fnum,
     485             :                                             uint16_t flags)
     486             : {
     487           0 :         struct tevent_req *req, *subreq;
     488           0 :         struct cli_smb2_close_fnum_state *state;
     489           0 :         NTSTATUS status;
     490             : 
     491       47482 :         req = tevent_req_create(mem_ctx, &state,
     492             :                                 struct cli_smb2_close_fnum_state);
     493       47482 :         if (req == NULL) {
     494           0 :                 return NULL;
     495             :         }
     496       47482 :         state->cli = cli;
     497       47482 :         state->fnum = fnum;
     498             : 
     499       47482 :         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
     500       47482 :         if (tevent_req_nterror(req, status)) {
     501           6 :                 return tevent_req_post(req, ev);
     502             :         }
     503             : 
     504       47476 :         subreq = smb2cli_close_send(state,
     505             :                                     ev,
     506             :                                     cli->conn,
     507       47476 :                                     cli->timeout,
     508             :                                     cli->smb2.session,
     509             :                                     cli->smb2.tcon,
     510             :                                     flags,
     511       47476 :                                     state->ph->fid_persistent,
     512       47476 :                                     state->ph->fid_volatile);
     513       47476 :         if (tevent_req_nomem(subreq, req)) {
     514           0 :                 return tevent_req_post(req, ev);
     515             :         }
     516       47476 :         tevent_req_set_callback(subreq, cli_smb2_close_fnum_done, req);
     517       47476 :         return req;
     518             : }
     519             : 
     520       47476 : static void cli_smb2_close_fnum_done(struct tevent_req *subreq)
     521             : {
     522       47476 :         struct tevent_req *req = tevent_req_callback_data(
     523             :                 subreq, struct tevent_req);
     524       47476 :         struct cli_smb2_close_fnum_state *state = tevent_req_data(
     525             :                 req, struct cli_smb2_close_fnum_state);
     526           0 :         NTSTATUS status;
     527             : 
     528       47476 :         status = smb2cli_close_recv(subreq);
     529       47476 :         if (tevent_req_nterror(req, status)) {
     530           8 :                 return;
     531             :         }
     532             : 
     533             :         /* Delete the fnum -> handle mapping. */
     534       47468 :         status = delete_smb2_handle_mapping(state->cli, &state->ph,
     535       47468 :                                             state->fnum);
     536       47468 :         if (tevent_req_nterror(req, status)) {
     537           0 :                 return;
     538             :         }
     539       47468 :         tevent_req_done(req);
     540             : }
     541             : 
     542       26472 : NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req)
     543             : {
     544       26472 :         struct cli_smb2_close_fnum_state *state = tevent_req_data(
     545             :                 req, struct cli_smb2_close_fnum_state);
     546       26472 :         NTSTATUS status = NT_STATUS_OK;
     547             : 
     548       26472 :         if (tevent_req_is_nterror(req, &status)) {
     549           2 :                 state->cli->raw_status = status;
     550             :         }
     551       26472 :         tevent_req_received(req);
     552       26472 :         return status;
     553             : }
     554             : 
     555        6555 : NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
     556             : {
     557        6555 :         TALLOC_CTX *frame = talloc_stackframe();
     558           0 :         struct tevent_context *ev;
     559           0 :         struct tevent_req *req;
     560        6555 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     561             : 
     562        6555 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     563             :                 /*
     564             :                  * Can't use sync call while an async call is in flight
     565             :                  */
     566           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     567           0 :                 goto fail;
     568             :         }
     569        6555 :         ev = samba_tevent_context_init(frame);
     570        6555 :         if (ev == NULL) {
     571           0 :                 goto fail;
     572             :         }
     573        6555 :         req = cli_smb2_close_fnum_send(frame, ev, cli, fnum, 0);
     574        6555 :         if (req == NULL) {
     575           0 :                 goto fail;
     576             :         }
     577        6555 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     578           0 :                 goto fail;
     579             :         }
     580        6555 :         status = cli_smb2_close_fnum_recv(req);
     581        6555 :  fail:
     582        6555 :         TALLOC_FREE(frame);
     583        6555 :         return status;
     584             : }
     585             : 
     586             : struct cli_smb2_set_info_fnum_state {
     587             :         uint8_t dummy;
     588             : };
     589             : 
     590             : static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq);
     591             : 
     592        7768 : struct tevent_req *cli_smb2_set_info_fnum_send(
     593             :         TALLOC_CTX *mem_ctx,
     594             :         struct tevent_context *ev,
     595             :         struct cli_state *cli,
     596             :         uint16_t fnum,
     597             :         uint8_t in_info_type,
     598             :         uint8_t in_info_class,
     599             :         const DATA_BLOB *in_input_buffer,
     600             :         uint32_t in_additional_info)
     601             : {
     602        7768 :         struct tevent_req *req = NULL, *subreq = NULL;
     603        7768 :         struct cli_smb2_set_info_fnum_state *state = NULL;
     604        7768 :         struct smb2_hnd *ph = NULL;
     605           0 :         NTSTATUS status;
     606             : 
     607        7768 :         req = tevent_req_create(
     608             :                 mem_ctx, &state, struct cli_smb2_set_info_fnum_state);
     609        7768 :         if (req == NULL) {
     610           0 :                 return NULL;
     611             :         }
     612             : 
     613        7768 :         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
     614        7768 :         if (tevent_req_nterror(req, status)) {
     615           0 :                 return tevent_req_post(req, ev);
     616             :         }
     617             : 
     618        7768 :         subreq = smb2cli_set_info_send(
     619             :                 state,
     620             :                 ev,
     621             :                 cli->conn,
     622        7768 :                 cli->timeout,
     623             :                 cli->smb2.session,
     624             :                 cli->smb2.tcon,
     625             :                 in_info_type,
     626             :                 in_info_class,
     627             :                 in_input_buffer,
     628             :                 in_additional_info,
     629        7768 :                 ph->fid_persistent,
     630        7768 :                 ph->fid_volatile);
     631        7768 :         if (tevent_req_nomem(subreq, req)) {
     632           0 :                 return tevent_req_post(req, ev);
     633             :         }
     634        7768 :         tevent_req_set_callback(subreq, cli_smb2_set_info_fnum_done, req);
     635        7768 :         return req;
     636             : }
     637             : 
     638        7768 : static void cli_smb2_set_info_fnum_done(struct tevent_req *subreq)
     639             : {
     640        7768 :         NTSTATUS status = smb2cli_set_info_recv(subreq);
     641        7768 :         tevent_req_simple_finish_ntstatus(subreq, status);
     642        7768 : }
     643             : 
     644        7768 : NTSTATUS cli_smb2_set_info_fnum_recv(struct tevent_req *req)
     645             : {
     646        7768 :         return tevent_req_simple_recv_ntstatus(req);
     647             : }
     648             : 
     649        1345 : NTSTATUS cli_smb2_set_info_fnum(
     650             :         struct cli_state *cli,
     651             :         uint16_t fnum,
     652             :         uint8_t in_info_type,
     653             :         uint8_t in_info_class,
     654             :         const DATA_BLOB *in_input_buffer,
     655             :         uint32_t in_additional_info)
     656             : {
     657        1345 :         TALLOC_CTX *frame = talloc_stackframe();
     658        1345 :         struct tevent_context *ev = NULL;
     659        1345 :         struct tevent_req *req = NULL;
     660        1345 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     661           0 :         bool ok;
     662             : 
     663        1345 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     664             :                 /*
     665             :                  * Can't use sync call while an async call is in flight
     666             :                  */
     667           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     668           0 :                 goto fail;
     669             :         }
     670        1345 :         ev = samba_tevent_context_init(frame);
     671        1345 :         if (ev == NULL) {
     672           0 :                 goto fail;
     673             :         }
     674        1345 :         req = cli_smb2_set_info_fnum_send(
     675             :                 frame,
     676             :                 ev,
     677             :                 cli,
     678             :                 fnum,
     679             :                 in_info_type,
     680             :                 in_info_class,
     681             :                 in_input_buffer,
     682             :                 in_additional_info);
     683        1345 :         if (req == NULL) {
     684           0 :                 goto fail;
     685             :         }
     686        1345 :         ok = tevent_req_poll_ntstatus(req, ev, &status);
     687        1345 :         if (!ok) {
     688           0 :                 goto fail;
     689             :         }
     690        1345 :         status = cli_smb2_set_info_fnum_recv(req);
     691        1345 : fail:
     692        1345 :         TALLOC_FREE(frame);
     693        1345 :         return status;
     694             : }
     695             : 
     696             : struct cli_smb2_delete_on_close_state {
     697             :         struct cli_state *cli;
     698             :         uint8_t data[1];
     699             :         DATA_BLOB inbuf;
     700             : };
     701             : 
     702             : static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
     703             : 
     704        3576 : struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
     705             :                                         struct tevent_context *ev,
     706             :                                         struct cli_state *cli,
     707             :                                         uint16_t fnum,
     708             :                                         bool flag)
     709             : {
     710        3576 :         struct tevent_req *req = NULL;
     711        3576 :         struct cli_smb2_delete_on_close_state *state = NULL;
     712        3576 :         struct tevent_req *subreq = NULL;
     713             : 
     714        3576 :         req = tevent_req_create(mem_ctx, &state,
     715             :                                 struct cli_smb2_delete_on_close_state);
     716        3576 :         if (req == NULL) {
     717           0 :                 return NULL;
     718             :         }
     719        3576 :         state->cli = cli;
     720             : 
     721             :         /* Setup data array. */
     722        3576 :         SCVAL(&state->data[0], 0, flag ? 1 : 0);
     723        3576 :         state->inbuf.data = &state->data[0];
     724        3576 :         state->inbuf.length = 1;
     725             : 
     726        3576 :         subreq = cli_smb2_set_info_fnum_send(state,
     727             :                                              ev,
     728             :                                              cli,
     729             :                                              fnum,
     730             :                                              SMB2_0_INFO_FILE,
     731             :                                              FSCC_FILE_DISPOSITION_INFORMATION,
     732        3576 :                                              &state->inbuf,
     733             :                                              0);
     734        3576 :         if (tevent_req_nomem(subreq, req)) {
     735           0 :                 return tevent_req_post(req, ev);
     736             :         }
     737        3576 :         tevent_req_set_callback(subreq,
     738             :                                 cli_smb2_delete_on_close_done,
     739             :                                 req);
     740        3576 :         return req;
     741             : }
     742             : 
     743        3576 : static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
     744             : {
     745        3576 :         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
     746        3576 :         tevent_req_simple_finish_ntstatus(subreq, status);
     747        3576 : }
     748             : 
     749        3576 : NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
     750             : {
     751           0 :         struct cli_smb2_delete_on_close_state *state =
     752        3576 :                 tevent_req_data(req,
     753             :                 struct cli_smb2_delete_on_close_state);
     754           0 :         NTSTATUS status;
     755             : 
     756        3576 :         if (tevent_req_is_nterror(req, &status)) {
     757          62 :                 state->cli->raw_status = status;
     758          62 :                 tevent_req_received(req);
     759          62 :                 return status;
     760             :         }
     761             : 
     762        3514 :         state->cli->raw_status = NT_STATUS_OK;
     763        3514 :         tevent_req_received(req);
     764        3514 :         return NT_STATUS_OK;
     765             : }
     766             : 
     767           0 : NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
     768             : {
     769           0 :         TALLOC_CTX *frame = talloc_stackframe();
     770           0 :         struct tevent_context *ev;
     771           0 :         struct tevent_req *req;
     772           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     773             : 
     774           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     775             :                 /*
     776             :                  * Can't use sync call while an async call is in flight
     777             :                  */
     778           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     779           0 :                 goto fail;
     780             :         }
     781           0 :         ev = samba_tevent_context_init(frame);
     782           0 :         if (ev == NULL) {
     783           0 :                 goto fail;
     784             :         }
     785           0 :         req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
     786           0 :         if (req == NULL) {
     787           0 :                 goto fail;
     788             :         }
     789           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     790           0 :                 goto fail;
     791             :         }
     792           0 :         status = cli_smb2_delete_on_close_recv(req);
     793           0 :  fail:
     794           0 :         TALLOC_FREE(frame);
     795           0 :         return status;
     796             : }
     797             : 
     798             : struct cli_smb2_mkdir_state {
     799             :         struct tevent_context *ev;
     800             :         struct cli_state *cli;
     801             : };
     802             : 
     803             : static void cli_smb2_mkdir_opened(struct tevent_req *subreq);
     804             : static void cli_smb2_mkdir_closed(struct tevent_req *subreq);
     805             : 
     806        3328 : struct tevent_req *cli_smb2_mkdir_send(
     807             :         TALLOC_CTX *mem_ctx,
     808             :         struct tevent_context *ev,
     809             :         struct cli_state *cli,
     810             :         const char *dname)
     811             : {
     812        3328 :         struct tevent_req *req = NULL, *subreq = NULL;
     813        3328 :         struct cli_smb2_mkdir_state *state = NULL;
     814             : 
     815        3328 :         req = tevent_req_create(
     816             :                 mem_ctx, &state, struct cli_smb2_mkdir_state);
     817        3328 :         if (req == NULL) {
     818           0 :                 return NULL;
     819             :         }
     820        3328 :         state->ev = ev;
     821        3328 :         state->cli = cli;
     822             : 
     823             :         /* Ensure this is a directory. */
     824        3328 :         subreq = cli_smb2_create_fnum_send(
     825             :                 state,                             /* mem_ctx */
     826             :                 ev,                                /* ev */
     827             :                 cli,                               /* cli */
     828             :                 dname,                             /* fname */
     829        3328 :                 (struct cli_smb2_create_flags){0}, /* create_flags */
     830             :                 SMB2_IMPERSONATION_IMPERSONATION,  /* impersonation_level */
     831             :                 FILE_READ_ATTRIBUTES,              /* desired_access */
     832             :                 FILE_ATTRIBUTE_DIRECTORY,          /* file_attributes */
     833             :                 FILE_SHARE_READ|
     834             :                 FILE_SHARE_WRITE,                  /* share_access */
     835             :                 FILE_CREATE,                       /* create_disposition */
     836             :                 FILE_DIRECTORY_FILE,               /* create_options */
     837             :                 NULL);                             /* in_cblobs */
     838        3328 :         if (tevent_req_nomem(subreq, req)) {
     839           0 :                 return tevent_req_post(req, ev);
     840             :         }
     841        3328 :         tevent_req_set_callback(subreq, cli_smb2_mkdir_opened, req);
     842        3328 :         return req;
     843             : }
     844             : 
     845        3328 : static void cli_smb2_mkdir_opened(struct tevent_req *subreq)
     846             : {
     847        3328 :         struct tevent_req *req = tevent_req_callback_data(
     848             :                 subreq, struct tevent_req);
     849        3328 :         struct cli_smb2_mkdir_state *state = tevent_req_data(
     850             :                 req, struct cli_smb2_mkdir_state);
     851           0 :         NTSTATUS status;
     852        3328 :         uint16_t fnum = 0xffff;
     853             : 
     854        3328 :         status = cli_smb2_create_fnum_recv(
     855             :                 subreq, &fnum, NULL, NULL, NULL, NULL);
     856        3328 :         TALLOC_FREE(subreq);
     857        3328 :         if (tevent_req_nterror(req, status)) {
     858        1026 :                 return;
     859             :         }
     860             : 
     861           0 :         subreq =
     862        2302 :                 cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum, 0);
     863        2302 :         if (tevent_req_nomem(subreq, req)) {
     864           0 :                 return;
     865             :         }
     866        2302 :         tevent_req_set_callback(subreq, cli_smb2_mkdir_closed, req);
     867             : }
     868             : 
     869        2302 : static void cli_smb2_mkdir_closed(struct tevent_req *subreq)
     870             : {
     871        2302 :         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
     872        2302 :         tevent_req_simple_finish_ntstatus(subreq, status);
     873        2302 : }
     874             : 
     875        3328 : NTSTATUS cli_smb2_mkdir_recv(struct tevent_req *req)
     876             : {
     877        3328 :         return tevent_req_simple_recv_ntstatus(req);
     878             : }
     879             : 
     880             : struct cli_smb2_rmdir_state {
     881             :         struct tevent_context *ev;
     882             :         struct cli_state *cli;
     883             :         const char *dname;
     884             :         const struct smb2_create_blobs *in_cblobs;
     885             :         uint16_t fnum;
     886             :         NTSTATUS status;
     887             : };
     888             : 
     889             : static void cli_smb2_rmdir_opened1(struct tevent_req *subreq);
     890             : static void cli_smb2_rmdir_opened2(struct tevent_req *subreq);
     891             : static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq);
     892             : static void cli_smb2_rmdir_closed(struct tevent_req *subreq);
     893             : 
     894        2500 : struct tevent_req *cli_smb2_rmdir_send(
     895             :         TALLOC_CTX *mem_ctx,
     896             :         struct tevent_context *ev,
     897             :         struct cli_state *cli,
     898             :         const char *dname,
     899             :         const struct smb2_create_blobs *in_cblobs)
     900             : {
     901        2500 :         struct tevent_req *req = NULL, *subreq = NULL;
     902        2500 :         struct cli_smb2_rmdir_state *state = NULL;
     903             : 
     904        2500 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_rmdir_state);
     905        2500 :         if (req == NULL) {
     906           0 :                 return NULL;
     907             :         }
     908        2500 :         state->ev = ev;
     909        2500 :         state->cli = cli;
     910        2500 :         state->dname = dname;
     911        2500 :         state->in_cblobs = in_cblobs;
     912             : 
     913        2500 :         subreq = cli_smb2_create_fnum_send(
     914             :                 state,
     915        2500 :                 state->ev,
     916        2500 :                 state->cli,
     917        2500 :                 state->dname,
     918        2500 :                 (struct cli_smb2_create_flags){0},
     919             :                 SMB2_IMPERSONATION_IMPERSONATION,
     920             :                 DELETE_ACCESS,          /* desired_access */
     921             :                 FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
     922             :                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
     923             :                 FILE_OPEN,              /* create_disposition */
     924             :                 FILE_DIRECTORY_FILE,    /* create_options */
     925        2500 :                 state->in_cblobs);   /* in_cblobs */
     926        2500 :         if (tevent_req_nomem(subreq, req)) {
     927           0 :                 return tevent_req_post(req, ev);
     928             :         }
     929        2500 :         tevent_req_set_callback(subreq, cli_smb2_rmdir_opened1, req);
     930        2500 :         return req;
     931             : }
     932             : 
     933        2500 : static void cli_smb2_rmdir_opened1(struct tevent_req *subreq)
     934             : {
     935        2500 :         struct tevent_req *req = tevent_req_callback_data(
     936             :                 subreq, struct tevent_req);
     937        2500 :         struct cli_smb2_rmdir_state *state = tevent_req_data(
     938             :                 req, struct cli_smb2_rmdir_state);
     939           0 :         NTSTATUS status;
     940             : 
     941        2500 :         status = cli_smb2_create_fnum_recv(
     942             :                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
     943        2500 :         TALLOC_FREE(subreq);
     944             : 
     945        2500 :         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
     946             :                 /*
     947             :                  * Naive option to match our SMB1 code. Assume the
     948             :                  * symlink path that tripped us up was the last
     949             :                  * component and try again. Eventually we will have to
     950             :                  * deal with the returned path unprocessed component. JRA.
     951             :                  */
     952           0 :                 subreq = cli_smb2_create_fnum_send(
     953             :                         state,
     954             :                         state->ev,
     955             :                         state->cli,
     956             :                         state->dname,
     957           0 :                         (struct cli_smb2_create_flags){0},
     958             :                         SMB2_IMPERSONATION_IMPERSONATION,
     959             :                         DELETE_ACCESS,          /* desired_access */
     960             :                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
     961             :                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
     962             :                         FILE_OPEN,              /* create_disposition */
     963             :                         FILE_DIRECTORY_FILE|
     964             :                         FILE_DELETE_ON_CLOSE|
     965             :                         FILE_OPEN_REPARSE_POINT, /* create_options */
     966             :                         state->in_cblobs);    /* in_cblobs */
     967           0 :                 if (tevent_req_nomem(subreq, req)) {
     968           0 :                         return;
     969             :                 }
     970           0 :                 tevent_req_set_callback(subreq, cli_smb2_rmdir_opened2, req);
     971           0 :                 return;
     972             :         }
     973             : 
     974        2500 :         if (tevent_req_nterror(req, status)) {
     975          40 :                 return;
     976             :         }
     977             : 
     978        2460 :         subreq = cli_smb2_delete_on_close_send(
     979        2460 :                 state, state->ev, state->cli, state->fnum, true);
     980        2460 :         if (tevent_req_nomem(subreq, req)) {
     981           0 :                 return;
     982             :         }
     983        2460 :         tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
     984             : }
     985             : 
     986           0 : static void cli_smb2_rmdir_opened2(struct tevent_req *subreq)
     987             : {
     988           0 :         struct tevent_req *req = tevent_req_callback_data(
     989             :                 subreq, struct tevent_req);
     990           0 :         struct cli_smb2_rmdir_state *state = tevent_req_data(
     991             :                 req, struct cli_smb2_rmdir_state);
     992           0 :         NTSTATUS status;
     993             : 
     994           0 :         status = cli_smb2_create_fnum_recv(
     995             :                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
     996           0 :         TALLOC_FREE(subreq);
     997           0 :         if (tevent_req_nterror(req, status)) {
     998           0 :                 return;
     999             :         }
    1000             : 
    1001           0 :         subreq = cli_smb2_delete_on_close_send(
    1002           0 :                 state, state->ev, state->cli, state->fnum, true);
    1003           0 :         if (tevent_req_nomem(subreq, req)) {
    1004           0 :                 return;
    1005             :         }
    1006           0 :         tevent_req_set_callback(subreq, cli_smb2_rmdir_disp_set, req);
    1007             : }
    1008             : 
    1009        2460 : static void cli_smb2_rmdir_disp_set(struct tevent_req *subreq)
    1010             : {
    1011        2460 :         struct tevent_req *req = tevent_req_callback_data(
    1012             :                 subreq, struct tevent_req);
    1013        2460 :         struct cli_smb2_rmdir_state *state = tevent_req_data(
    1014             :                 req, struct cli_smb2_rmdir_state);
    1015             : 
    1016        2460 :         state->status = cli_smb2_delete_on_close_recv(subreq);
    1017        2460 :         TALLOC_FREE(subreq);
    1018             : 
    1019             :         /*
    1020             :          * Close the fd even if the set_disp failed
    1021             :          */
    1022             : 
    1023        2460 :         subreq = cli_smb2_close_fnum_send(state,
    1024             :                                           state->ev,
    1025             :                                           state->cli,
    1026        2460 :                                           state->fnum,
    1027             :                                           0);
    1028        2460 :         if (tevent_req_nomem(subreq, req)) {
    1029           0 :                 return;
    1030             :         }
    1031        2460 :         tevent_req_set_callback(subreq, cli_smb2_rmdir_closed, req);
    1032             : }
    1033             : 
    1034        2460 : static void cli_smb2_rmdir_closed(struct tevent_req *subreq)
    1035             : {
    1036        2460 :         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
    1037        2460 :         tevent_req_simple_finish_ntstatus(subreq, status);
    1038        2460 : }
    1039             : 
    1040        2500 : NTSTATUS cli_smb2_rmdir_recv(struct tevent_req *req)
    1041             : {
    1042        2500 :         struct cli_smb2_rmdir_state *state = tevent_req_data(
    1043             :                 req, struct cli_smb2_rmdir_state);
    1044           0 :         NTSTATUS status;
    1045             : 
    1046        2500 :         if (tevent_req_is_nterror(req, &status)) {
    1047          42 :                 return status;
    1048             :         }
    1049        2458 :         return state->status;
    1050             : }
    1051             : 
    1052             : /***************************************************************
    1053             :  Small wrapper that allows SMB2 to unlink a pathname.
    1054             : ***************************************************************/
    1055             : 
    1056             : struct cli_smb2_unlink_state {
    1057             :         struct tevent_context *ev;
    1058             :         struct cli_state *cli;
    1059             :         const char *fname;
    1060             :         const struct smb2_create_blobs *in_cblobs;
    1061             : };
    1062             : 
    1063             : static void cli_smb2_unlink_opened1(struct tevent_req *subreq);
    1064             : static void cli_smb2_unlink_opened2(struct tevent_req *subreq);
    1065             : static void cli_smb2_unlink_closed(struct tevent_req *subreq);
    1066             : 
    1067        2393 : struct tevent_req *cli_smb2_unlink_send(
    1068             :         TALLOC_CTX *mem_ctx,
    1069             :         struct tevent_context *ev,
    1070             :         struct cli_state *cli,
    1071             :         const char *fname,
    1072             :         const struct smb2_create_blobs *in_cblobs)
    1073             : {
    1074        2393 :         struct tevent_req *req = NULL, *subreq = NULL;
    1075        2393 :         struct cli_smb2_unlink_state *state = NULL;
    1076             : 
    1077        2393 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_unlink_state);
    1078        2393 :         if (req == NULL) {
    1079           0 :                 return NULL;
    1080             :         }
    1081        2393 :         state->ev = ev;
    1082        2393 :         state->cli = cli;
    1083        2393 :         state->fname = fname;
    1084        2393 :         state->in_cblobs = in_cblobs;
    1085             : 
    1086        2393 :         subreq = cli_smb2_create_fnum_send(
    1087             :                 state,          /* mem_ctx */
    1088        2393 :                 state->ev,   /* tevent_context */
    1089        2393 :                 state->cli,  /* cli_struct */
    1090        2393 :                 state->fname,        /* filename */
    1091        2393 :                 (struct cli_smb2_create_flags){0},
    1092             :                 SMB2_IMPERSONATION_IMPERSONATION,
    1093             :                 DELETE_ACCESS,          /* desired_access */
    1094             :                 FILE_ATTRIBUTE_NORMAL, /* file attributes */
    1095             :                 FILE_SHARE_READ|
    1096             :                 FILE_SHARE_WRITE|
    1097             :                 FILE_SHARE_DELETE, /* share_access */
    1098             :                 FILE_OPEN,              /* create_disposition */
    1099             :                 FILE_DELETE_ON_CLOSE,   /* create_options */
    1100        2393 :                 state->in_cblobs);   /* in_cblobs */
    1101        2393 :         if (tevent_req_nomem(subreq, req)) {
    1102           0 :                 return tevent_req_post(req, ev);
    1103             :         }
    1104        2393 :         tevent_req_set_callback(subreq, cli_smb2_unlink_opened1, req);
    1105        2393 :         return req;
    1106             : }
    1107             : 
    1108        2393 : static void cli_smb2_unlink_opened1(struct tevent_req *subreq)
    1109             : {
    1110        2393 :         struct tevent_req *req = tevent_req_callback_data(
    1111             :                 subreq, struct tevent_req);
    1112        2393 :         struct cli_smb2_unlink_state *state = tevent_req_data(
    1113             :                 req, struct cli_smb2_unlink_state);
    1114        2393 :         uint16_t fnum = 0xffff;
    1115           0 :         NTSTATUS status;
    1116             : 
    1117        2393 :         status = cli_smb2_create_fnum_recv(
    1118             :                 subreq, &fnum, NULL, NULL, NULL, NULL);
    1119        2393 :         TALLOC_FREE(subreq);
    1120             : 
    1121        2393 :         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) ||
    1122        2393 :             NT_STATUS_EQUAL(status, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED)) {
    1123             :                 /*
    1124             :                  * Naive option to match our SMB1 code. Assume the
    1125             :                  * symlink path that tripped us up was the last
    1126             :                  * component and try again. Eventually we will have to
    1127             :                  * deal with the returned path unprocessed component. JRA.
    1128             :                  */
    1129           0 :                 subreq = cli_smb2_create_fnum_send(
    1130             :                         state,          /* mem_ctx */
    1131             :                         state->ev,   /* tevent_context */
    1132             :                         state->cli,  /* cli_struct */
    1133             :                         state->fname,        /* filename */
    1134           0 :                         (struct cli_smb2_create_flags){0},
    1135             :                         SMB2_IMPERSONATION_IMPERSONATION,
    1136             :                         DELETE_ACCESS,          /* desired_access */
    1137             :                         FILE_ATTRIBUTE_NORMAL, /* file attributes */
    1138             :                         FILE_SHARE_READ|
    1139             :                         FILE_SHARE_WRITE|
    1140             :                         FILE_SHARE_DELETE, /* share_access */
    1141             :                         FILE_OPEN,              /* create_disposition */
    1142             :                         FILE_DELETE_ON_CLOSE|
    1143             :                         FILE_OPEN_REPARSE_POINT, /* create_options */
    1144             :                         state->in_cblobs);    /* in_cblobs */
    1145           0 :                 if (tevent_req_nomem(subreq, req)) {
    1146           0 :                         return;
    1147             :                 }
    1148           0 :                 tevent_req_set_callback(subreq, cli_smb2_unlink_opened2, req);
    1149           0 :                 return;
    1150             :         }
    1151             : 
    1152        2393 :         if (tevent_req_nterror(req, status)) {
    1153         288 :                 return;
    1154             :         }
    1155             : 
    1156           0 :         subreq =
    1157        2105 :                 cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum, 0);
    1158        2105 :         if (tevent_req_nomem(subreq, req)) {
    1159           0 :                 return;
    1160             :         }
    1161        2105 :         tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
    1162             : }
    1163             : 
    1164           0 : static void cli_smb2_unlink_opened2(struct tevent_req *subreq)
    1165             : {
    1166           0 :         struct tevent_req *req = tevent_req_callback_data(
    1167             :                 subreq, struct tevent_req);
    1168           0 :         struct cli_smb2_unlink_state *state = tevent_req_data(
    1169             :                 req, struct cli_smb2_unlink_state);
    1170           0 :         uint16_t fnum = 0xffff;
    1171           0 :         NTSTATUS status;
    1172             : 
    1173           0 :         status = cli_smb2_create_fnum_recv(
    1174             :                 subreq, &fnum, NULL, NULL, NULL, NULL);
    1175           0 :         TALLOC_FREE(subreq);
    1176           0 :         if (tevent_req_nterror(req, status)) {
    1177           0 :                 return;
    1178             :         }
    1179             : 
    1180           0 :         subreq =
    1181           0 :                 cli_smb2_close_fnum_send(state, state->ev, state->cli, fnum, 0);
    1182           0 :         if (tevent_req_nomem(subreq, req)) {
    1183           0 :                 return;
    1184             :         }
    1185           0 :         tevent_req_set_callback(subreq, cli_smb2_unlink_closed, req);
    1186             : }
    1187             : 
    1188        2105 : static void cli_smb2_unlink_closed(struct tevent_req *subreq)
    1189             : {
    1190        2105 :         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
    1191        2105 :         tevent_req_simple_finish_ntstatus(subreq, status);
    1192        2105 : }
    1193             : 
    1194        2393 : NTSTATUS cli_smb2_unlink_recv(struct tevent_req *req)
    1195             : {
    1196        2393 :         return tevent_req_simple_recv_ntstatus(req);
    1197             : }
    1198             : 
    1199             : /***************************************************************
    1200             :  Utility function to parse a SMB2_FIND_POSIX_INFORMATION reply.
    1201             : ***************************************************************/
    1202             : 
    1203        1449 : static NTSTATUS parse_finfo_posix_info(const uint8_t *dir_data,
    1204             :                                        uint32_t dir_data_length,
    1205             :                                        struct file_info *finfo,
    1206             :                                        uint32_t *next_offset)
    1207             : {
    1208        1449 :         struct smb3_file_posix_information info = {};
    1209           0 :         size_t consumed;
    1210           0 :         enum ndr_err_code ndr_err;
    1211        1449 :         size_t namelen = 0;
    1212        1449 :         size_t ret = 0;
    1213        1449 :         uint32_t _next_offset = 0;
    1214             : 
    1215        1449 :         if (dir_data_length < 4) {
    1216           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1217             :         }
    1218             : 
    1219        1449 :         _next_offset = IVAL(dir_data, 0);
    1220             : 
    1221        1449 :         if (_next_offset > dir_data_length) {
    1222           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1223             :         }
    1224             : 
    1225        1449 :         if (_next_offset != 0) {
    1226             :                 /* Ensure we only read what in this record. */
    1227        1443 :                 dir_data_length = _next_offset;
    1228             :         }
    1229             : 
    1230             :         /*
    1231             :          * Skip NextEntryOffset and FileIndex
    1232             :          */
    1233        1449 :         if (dir_data_length < 8) {
    1234           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1235             :         }
    1236        1449 :         dir_data += 8;
    1237        1449 :         dir_data_length -= 8;
    1238             : 
    1239        1449 :         ndr_err = ndr_pull_struct_blob_noalloc(
    1240             :                 dir_data,
    1241             :                 dir_data_length,
    1242             :                 &info,
    1243             :                 (ndr_pull_flags_fn_t)ndr_pull_smb3_file_posix_information,
    1244             :                 &consumed);
    1245        1449 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1246           0 :                 return ndr_map_error2ntstatus(ndr_err);
    1247             :         }
    1248        1449 :         if (consumed > dir_data_length) {
    1249           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1250             :         }
    1251        1449 :         dir_data += consumed;
    1252        1449 :         dir_data_length -= consumed;
    1253             : 
    1254        1449 :         finfo->btime_ts = interpret_long_date(info.creation_time);
    1255        1449 :         finfo->atime_ts = interpret_long_date(info.last_access_time);
    1256        1449 :         finfo->mtime_ts = interpret_long_date(info.last_write_time);
    1257        1449 :         finfo->ctime_ts = interpret_long_date(info.change_time);
    1258        1449 :         finfo->allocated_size = info.allocation_size;
    1259        1449 :         finfo->size = info.end_of_file;
    1260        1449 :         finfo->attr = info.file_attributes;
    1261        1449 :         finfo->ino = info.inode;
    1262        1449 :         finfo->st_ex_dev = info.device;
    1263        1449 :         finfo->st_ex_nlink = info.cc.nlinks;
    1264        1449 :         finfo->reparse_tag = info.cc.reparse_tag;
    1265        1449 :         finfo->st_ex_mode = wire_perms_to_unix(info.cc.posix_perms);
    1266        1449 :         sid_copy(&finfo->owner_sid, &info.cc.owner);
    1267        1449 :         sid_copy(&finfo->group_sid, &info.cc.group);
    1268             : 
    1269        1449 :         if (dir_data_length < 4) {
    1270           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1271             :         }
    1272        1449 :         namelen = PULL_LE_U32(dir_data, 0);
    1273             : 
    1274        1449 :         dir_data += 4;
    1275        1449 :         dir_data_length -= 4;
    1276             : 
    1277        1449 :         if (namelen > dir_data_length) {
    1278           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1279             :         }
    1280             : 
    1281        1449 :         ret = pull_string_talloc(finfo,
    1282             :                                  dir_data,
    1283             :                                  FLAGS2_UNICODE_STRINGS,
    1284             :                                  &finfo->name,
    1285             :                                  dir_data,
    1286             :                                  namelen,
    1287             :                                  STR_UNICODE);
    1288        1449 :         if (ret == (size_t)-1) {
    1289             :                 /* Bad conversion. */
    1290           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    1291             :         }
    1292             : 
    1293        1449 :         if (finfo->name == NULL) {
    1294             :                 /* Bad conversion. */
    1295           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    1296             :         }
    1297             : 
    1298        1449 :         *next_offset = _next_offset;
    1299        1449 :         return NT_STATUS_OK;
    1300             : }
    1301             : 
    1302             : /***************************************************************
    1303             :  Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply.
    1304             : ***************************************************************/
    1305             : 
    1306       54559 : static NTSTATUS parse_finfo_id_both_directory_info(const uint8_t *dir_data,
    1307             :                                 uint32_t dir_data_length,
    1308             :                                 struct file_info *finfo,
    1309             :                                 uint32_t *next_offset)
    1310             : {
    1311       54559 :         size_t namelen = 0;
    1312       54559 :         size_t slen = 0;
    1313       54559 :         size_t ret = 0;
    1314             : 
    1315       54559 :         if (dir_data_length < 4) {
    1316           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1317             :         }
    1318             : 
    1319       54559 :         *next_offset = IVAL(dir_data, 0);
    1320             : 
    1321       54559 :         if (*next_offset > dir_data_length) {
    1322           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1323             :         }
    1324             : 
    1325       54559 :         if (*next_offset != 0) {
    1326             :                 /* Ensure we only read what in this record. */
    1327       46246 :                 dir_data_length = *next_offset;
    1328             :         }
    1329             : 
    1330       54559 :         if (dir_data_length < 105) {
    1331           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1332             :         }
    1333             : 
    1334       54559 :         finfo->btime_ts = interpret_long_date(BVAL(dir_data, 8));
    1335       54559 :         finfo->atime_ts = interpret_long_date(BVAL(dir_data, 16));
    1336       54559 :         finfo->mtime_ts = interpret_long_date(BVAL(dir_data, 24));
    1337       54559 :         finfo->ctime_ts = interpret_long_date(BVAL(dir_data, 32));
    1338       54559 :         finfo->size = BVAL(dir_data + 40, 0);
    1339       54559 :         finfo->allocated_size = BVAL(dir_data + 48, 0);
    1340       54559 :         finfo->attr = IVAL(dir_data + 56, 0);
    1341       54559 :         finfo->ino = BVAL(dir_data + 96, 0);
    1342       54559 :         namelen = IVAL(dir_data + 60,0);
    1343       54559 :         if (namelen > (dir_data_length - 104)) {
    1344           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1345             :         }
    1346       54559 :         finfo->reparse_tag = IVAL(dir_data + 64, 0);
    1347       54559 :         slen = CVAL(dir_data + 68, 0);
    1348       54559 :         if (slen > 24) {
    1349           0 :                 return NT_STATUS_INFO_LENGTH_MISMATCH;
    1350             :         }
    1351       54559 :         ret = pull_string_talloc(finfo,
    1352             :                                 dir_data,
    1353             :                                 FLAGS2_UNICODE_STRINGS,
    1354             :                                 &finfo->short_name,
    1355       54559 :                                 dir_data + 70,
    1356             :                                 slen,
    1357             :                                 STR_UNICODE);
    1358       54559 :         if (ret == (size_t)-1) {
    1359             :                 /* Bad conversion. */
    1360           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    1361             :         }
    1362             : 
    1363       54559 :         ret = pull_string_talloc(finfo,
    1364             :                                 dir_data,
    1365             :                                 FLAGS2_UNICODE_STRINGS,
    1366             :                                 &finfo->name,
    1367       54559 :                                 dir_data + 104,
    1368             :                                 namelen,
    1369             :                                 STR_UNICODE);
    1370       54559 :         if (ret == (size_t)-1) {
    1371             :                 /* Bad conversion. */
    1372           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    1373             :         }
    1374             : 
    1375       54559 :         if (finfo->name == NULL) {
    1376             :                 /* Bad conversion. */
    1377           2 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    1378             :         }
    1379             : 
    1380       54557 :         return NT_STATUS_OK;
    1381             : }
    1382             : 
    1383             : /*******************************************************************
    1384             :  Given a filename - get its directory name
    1385             : ********************************************************************/
    1386             : 
    1387        8826 : static bool windows_parent_dirname(TALLOC_CTX *mem_ctx,
    1388             :                                 const char *dir,
    1389             :                                 char **parent,
    1390             :                                 const char **name)
    1391             : {
    1392           0 :         char *p;
    1393           0 :         ptrdiff_t len;
    1394             : 
    1395        8826 :         p = strrchr_m(dir, '\\'); /* Find final '\\', if any */
    1396             : 
    1397        8826 :         if (p == NULL) {
    1398          94 :                 if (!(*parent = talloc_strdup(mem_ctx, "\\"))) {
    1399           0 :                         return false;
    1400             :                 }
    1401          94 :                 if (name) {
    1402          94 :                         *name = dir;
    1403             :                 }
    1404          94 :                 return true;
    1405             :         }
    1406             : 
    1407        8732 :         len = p-dir;
    1408             : 
    1409        8732 :         if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) {
    1410           0 :                 return false;
    1411             :         }
    1412        8732 :         (*parent)[len] = '\0';
    1413             : 
    1414        8732 :         if (name) {
    1415        8732 :                 *name = p+1;
    1416             :         }
    1417        8732 :         return true;
    1418             : }
    1419             : 
    1420             : struct cli_smb2_list_dir_data {
    1421             :         uint8_t *data;
    1422             :         uint32_t length;
    1423             : };
    1424             : 
    1425             : struct cli_smb2_list_state {
    1426             :         struct tevent_context *ev;
    1427             :         struct cli_state *cli;
    1428             :         const char *mask;
    1429             : 
    1430             :         uint16_t fnum;
    1431             : 
    1432             :         NTSTATUS status;
    1433             :         struct cli_smb2_list_dir_data *response;
    1434             :         uint32_t offset;
    1435             :         unsigned int info_level;
    1436             : };
    1437             : 
    1438             : static void cli_smb2_list_opened(struct tevent_req *subreq);
    1439             : static void cli_smb2_list_done(struct tevent_req *subreq);
    1440             : static void cli_smb2_list_closed(struct tevent_req *subreq);
    1441             : 
    1442        8826 : struct tevent_req *cli_smb2_list_send(
    1443             :         TALLOC_CTX *mem_ctx,
    1444             :         struct tevent_context *ev,
    1445             :         struct cli_state *cli,
    1446             :         const char *pathname,
    1447             :         unsigned int info_level)
    1448             : {
    1449        8826 :         struct tevent_req *req = NULL, *subreq = NULL;
    1450        8826 :         struct cli_smb2_list_state *state = NULL;
    1451        8826 :         char *parent = NULL;
    1452           0 :         bool ok;
    1453        8826 :         struct smb2_create_blobs *in_cblobs = NULL;
    1454             : 
    1455        8826 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_list_state);
    1456        8826 :         if (req == NULL) {
    1457           0 :                 return NULL;
    1458             :         }
    1459        8826 :         state->ev = ev;
    1460        8826 :         state->cli = cli;
    1461        8826 :         state->status = NT_STATUS_OK;
    1462        8826 :         state->info_level = info_level;
    1463             : 
    1464        8826 :         ok = windows_parent_dirname(state, pathname, &parent, &state->mask);
    1465        8826 :         if (!ok) {
    1466           0 :                 tevent_req_oom(req);
    1467           0 :                 return tevent_req_post(req, ev);
    1468             :         }
    1469             : 
    1470        8826 :         if (smbXcli_conn_have_posix(cli->conn) &&
    1471             :                 info_level == SMB2_FIND_POSIX_INFORMATION)
    1472             :         {
    1473           0 :                 NTSTATUS status;
    1474             : 
    1475             :                 /* The mode MUST be 0 when opening an existing file/dir, and
    1476             :                  * will be ignored by the server.
    1477             :                  */
    1478           6 :                 uint8_t linear_mode[4] = { 0 };
    1479           6 :                 DATA_BLOB blob = { .data=linear_mode,
    1480             :                                    .length=sizeof(linear_mode) };
    1481             : 
    1482           6 :                 in_cblobs = talloc_zero(mem_ctx, struct smb2_create_blobs);
    1483           6 :                 if (in_cblobs == NULL) {
    1484           0 :                         return NULL;
    1485             :                 }
    1486             : 
    1487           6 :                 status = smb2_create_blob_add(in_cblobs, in_cblobs,
    1488             :                                               SMB2_CREATE_TAG_POSIX, blob);
    1489           6 :                 if (tevent_req_nterror(req, status)) {
    1490           0 :                         tevent_req_nterror(req, status);
    1491           0 :                         return tevent_req_post(req, ev);
    1492             :                 }
    1493             :         }
    1494             : 
    1495        8826 :         subreq = cli_smb2_create_fnum_send(
    1496             :                 state,                                  /* mem_ctx */
    1497             :                 ev,                                     /* ev */
    1498             :                 cli,                                    /* cli */
    1499             :                 parent,                                 /* fname */
    1500        8826 :                 (struct cli_smb2_create_flags){0},      /* create_flags */
    1501             :                 SMB2_IMPERSONATION_IMPERSONATION,       /* impersonation_level */
    1502             :                 SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,    /* desired_access */
    1503             :                 FILE_ATTRIBUTE_DIRECTORY,               /* file_attributes */
    1504             :                 FILE_SHARE_READ|FILE_SHARE_WRITE,       /* share_access */
    1505             :                 FILE_OPEN,                              /* create_disposition */
    1506             :                 FILE_DIRECTORY_FILE,                    /* create_options */
    1507             :                 in_cblobs);                             /* in_cblobs */
    1508        8826 :         TALLOC_FREE(in_cblobs);
    1509        8826 :         if (tevent_req_nomem(subreq, req)) {
    1510           0 :                 return tevent_req_post(req, ev);
    1511             :         }
    1512        8826 :         tevent_req_set_callback(subreq, cli_smb2_list_opened, req);
    1513        8826 :         return req;
    1514             : }
    1515             : 
    1516        8826 : static void cli_smb2_list_opened(struct tevent_req *subreq)
    1517             : {
    1518        8826 :         struct tevent_req *req = tevent_req_callback_data(
    1519             :                 subreq, struct tevent_req);
    1520        8826 :         struct cli_smb2_list_state *state = tevent_req_data(
    1521             :                 req, struct cli_smb2_list_state);
    1522           0 :         NTSTATUS status;
    1523             : 
    1524        8826 :         status = cli_smb2_create_fnum_recv(
    1525             :                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
    1526        8826 :         TALLOC_FREE(subreq);
    1527        8826 :         if (tevent_req_nterror(req, status)) {
    1528         280 :                 return;
    1529             :         }
    1530             : 
    1531             :         /*
    1532             :          * Make our caller get back to us via cli_smb2_list_recv(),
    1533             :          * triggering the smb2_query_directory_send()
    1534             :          */
    1535        8546 :         tevent_req_defer_callback(req, state->ev);
    1536        8546 :         tevent_req_notify_callback(req);
    1537             : }
    1538             : 
    1539       16863 : static void cli_smb2_list_done(struct tevent_req *subreq)
    1540             : {
    1541       16863 :         struct tevent_req *req = tevent_req_callback_data(
    1542             :                 subreq, struct tevent_req);
    1543       16863 :         struct cli_smb2_list_state *state = tevent_req_data(
    1544             :                 req, struct cli_smb2_list_state);
    1545       16863 :         struct cli_smb2_list_dir_data *response = NULL;
    1546             : 
    1547       16863 :         response = talloc(state, struct cli_smb2_list_dir_data);
    1548       16863 :         if (tevent_req_nomem(response, req)) {
    1549           0 :                 return;
    1550             :         }
    1551             : 
    1552       16863 :         state->status = smb2cli_query_directory_recv(
    1553             :                 subreq, response, &response->data, &response->length);
    1554       16863 :         TALLOC_FREE(subreq);
    1555             : 
    1556       16863 :         if (NT_STATUS_IS_OK(state->status)) {
    1557        8319 :                 state->response = response;
    1558        8319 :                 state->offset = 0;
    1559             : 
    1560        8319 :                 tevent_req_defer_callback(req, state->ev);
    1561        8319 :                 tevent_req_notify_callback(req);
    1562        8319 :                 return;
    1563             :         }
    1564             : 
    1565        8544 :         TALLOC_FREE(response);
    1566             : 
    1567        8544 :         subreq = cli_smb2_close_fnum_send(state,
    1568             :                                           state->ev,
    1569             :                                           state->cli,
    1570        8544 :                                           state->fnum,
    1571             :                                           0);
    1572        8544 :         if (tevent_req_nomem(subreq, req)) {
    1573           0 :                 return;
    1574             :         }
    1575        8544 :         tevent_req_set_callback(subreq, cli_smb2_list_closed, req);
    1576             : }
    1577             : 
    1578        8544 : static void cli_smb2_list_closed(struct tevent_req *subreq)
    1579             : {
    1580        8544 :         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
    1581        8544 :         tevent_req_simple_finish_ntstatus(subreq, status);
    1582        8544 : }
    1583             : 
    1584             : /*
    1585             :  * Return the next finfo directory.
    1586             :  *
    1587             :  * This parses the blob returned from QUERY_DIRECTORY step by step. If
    1588             :  * the blob ends, this triggers a fresh QUERY_DIRECTORY and returns
    1589             :  * NT_STATUS_RETRY, which will then trigger the caller again when the
    1590             :  * QUERY_DIRECTORY has returned with another buffer. This way we
    1591             :  * guarantee that no asynchronous request is open after this call
    1592             :  * returns an entry, so that other synchronous requests can be issued
    1593             :  * on the same connection while the directory listing proceeds.
    1594             :  */
    1595       81695 : NTSTATUS cli_smb2_list_recv(
    1596             :         struct tevent_req *req,
    1597             :         TALLOC_CTX *mem_ctx,
    1598             :         struct file_info **pfinfo)
    1599             : {
    1600       81695 :         struct cli_smb2_list_state *state = tevent_req_data(
    1601             :                 req, struct cli_smb2_list_state);
    1602       81695 :         struct cli_smb2_list_dir_data *response = NULL;
    1603       81695 :         struct file_info *finfo = NULL;
    1604           0 :         NTSTATUS status;
    1605       81695 :         uint32_t next_offset = 0;
    1606           0 :         bool in_progress;
    1607             : 
    1608       81695 :         in_progress = tevent_req_is_in_progress(req);
    1609             : 
    1610       81695 :         if (!in_progress) {
    1611        8824 :                 if (!tevent_req_is_nterror(req, &status)) {
    1612        8544 :                         status = NT_STATUS_NO_MORE_FILES;
    1613             :                 }
    1614        8824 :                 goto fail;
    1615             :         }
    1616             : 
    1617       72871 :         response = state->response;
    1618       72871 :         if (response == NULL) {
    1619       16863 :                 struct tevent_req *subreq = NULL;
    1620       16863 :                 struct cli_state *cli = state->cli;
    1621       16863 :                 struct smb2_hnd *ph = NULL;
    1622           0 :                 uint32_t max_trans, max_avail_len;
    1623           0 :                 bool ok;
    1624             : 
    1625       16863 :                 if (!NT_STATUS_IS_OK(state->status)) {
    1626           0 :                         status = state->status;
    1627           0 :                         goto fail;
    1628             :                 }
    1629             : 
    1630       16863 :                 status = map_fnum_to_smb2_handle(cli, state->fnum, &ph);
    1631       16863 :                 if (!NT_STATUS_IS_OK(status)) {
    1632           0 :                         goto fail;
    1633             :                 }
    1634             : 
    1635       16863 :                 max_trans = smb2cli_conn_max_trans_size(cli->conn);
    1636       16863 :                 ok = smb2cli_conn_req_possible(cli->conn, &max_avail_len);
    1637       16863 :                 if (ok) {
    1638       16863 :                         max_trans = MIN(max_trans, max_avail_len);
    1639             :                 }
    1640             : 
    1641       16863 :                 subreq = smb2cli_query_directory_send(
    1642             :                         state,                          /* mem_ctx */
    1643             :                         state->ev,                   /* ev */
    1644             :                         cli->conn,                   /* conn */
    1645       16863 :                         cli->timeout,                        /* timeout_msec */
    1646             :                         cli->smb2.session,           /* session */
    1647             :                         cli->smb2.tcon,                      /* tcon */
    1648       16863 :                         state->info_level,           /* level */
    1649             :                         0,                              /* flags */
    1650             :                         0,                              /* file_index */
    1651       16863 :                         ph->fid_persistent,          /* fid_persistent */
    1652       16863 :                         ph->fid_volatile,            /* fid_volatile */
    1653             :                         state->mask,                 /* mask */
    1654             :                         max_trans);                     /* outbuf_len */
    1655       16863 :                 if (subreq == NULL) {
    1656           0 :                         status = NT_STATUS_NO_MEMORY;
    1657           0 :                         goto fail;
    1658             :                 }
    1659       16863 :                 tevent_req_set_callback(subreq, cli_smb2_list_done, req);
    1660       16863 :                 return NT_STATUS_RETRY;
    1661             :         }
    1662             : 
    1663       56008 :         SMB_ASSERT(response->length > state->offset);
    1664             : 
    1665       56008 :         finfo = talloc_zero(mem_ctx, struct file_info);
    1666       56008 :         if (finfo == NULL) {
    1667           0 :                 status = NT_STATUS_NO_MEMORY;
    1668           0 :                 goto fail;
    1669             :         }
    1670             : 
    1671       56008 :         if (state->info_level == SMB2_FIND_POSIX_INFORMATION) {
    1672        1449 :                 status = parse_finfo_posix_info(
    1673        1449 :                         response->data + state->offset,
    1674        1449 :                         response->length - state->offset,
    1675             :                         finfo,
    1676             :                         &next_offset);
    1677             :         } else {
    1678       54559 :                 status = parse_finfo_id_both_directory_info(
    1679       54559 :                         response->data + state->offset,
    1680       54559 :                         response->length - state->offset,
    1681             :                         finfo,
    1682             :                         &next_offset);
    1683             :         }
    1684       56008 :         if (!NT_STATUS_IS_OK(status)) {
    1685           2 :                 goto fail;
    1686             :         }
    1687             : 
    1688       56006 :         status = is_bad_finfo_name(state->cli, finfo);
    1689       56006 :         if (!NT_STATUS_IS_OK(status)) {
    1690           0 :                 goto fail;
    1691             :         }
    1692             : 
    1693             :         /*
    1694             :          * parse_finfo_id_both_directory_info() checks for overflow,
    1695             :          * no need to check again here.
    1696             :          */
    1697       56006 :         state->offset += next_offset;
    1698             : 
    1699       56006 :         if (next_offset == 0) {
    1700        8317 :                 TALLOC_FREE(state->response);
    1701             :         }
    1702             : 
    1703       56006 :         tevent_req_defer_callback(req, state->ev);
    1704       56006 :         tevent_req_notify_callback(req);
    1705             : 
    1706       56006 :         *pfinfo = finfo;
    1707       56006 :         return NT_STATUS_OK;
    1708             : 
    1709        8826 : fail:
    1710        8826 :         TALLOC_FREE(finfo);
    1711        8826 :         tevent_req_received(req);
    1712        8826 :         return status;
    1713             : }
    1714             : 
    1715             : /***************************************************************
    1716             :  Wrapper that allows SMB2 to query a path info (basic level).
    1717             :  Synchronous only.
    1718             : ***************************************************************/
    1719             : 
    1720        8126 : NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli,
    1721             :                                 const char *name,
    1722             :                                 SMB_STRUCT_STAT *sbuf,
    1723             :                                 uint32_t *attributes)
    1724             : {
    1725           0 :         NTSTATUS status;
    1726           0 :         struct smb_create_returns cr;
    1727        8126 :         uint16_t fnum = 0xffff;
    1728        8126 :         size_t namelen = strlen(name);
    1729             : 
    1730        8126 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    1731             :                 /*
    1732             :                  * Can't use sync call while an async call is in flight
    1733             :                  */
    1734           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1735             :         }
    1736             : 
    1737             :         /* SMB2 is pickier about pathnames. Ensure it doesn't
    1738             :            end in a '\' */
    1739        8126 :         if (namelen > 0 && name[namelen-1] == '\\') {
    1740         168 :                 char *modname = talloc_strndup(talloc_tos(), name, namelen-1);
    1741         168 :                 if (modname == NULL) {
    1742           0 :                         return NT_STATUS_NO_MEMORY;
    1743             :                 }
    1744         168 :                 name = modname;
    1745             :         }
    1746             : 
    1747             :         /* This is commonly used as a 'cd'. Try qpathinfo on
    1748             :            a directory handle first. */
    1749             : 
    1750        8126 :         status = cli_smb2_create_fnum(cli,
    1751             :                         name,
    1752        8126 :                         (struct cli_smb2_create_flags){0},
    1753             :                         SMB2_IMPERSONATION_IMPERSONATION,
    1754             :                         FILE_READ_ATTRIBUTES,   /* desired_access */
    1755             :                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
    1756             :                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
    1757             :                         FILE_OPEN,              /* create_disposition */
    1758             :                         FILE_DIRECTORY_FILE,    /* create_options */
    1759             :                         NULL,
    1760             :                         &fnum,
    1761             :                         &cr,
    1762             :                         NULL,
    1763             :                         NULL);
    1764             : 
    1765        8126 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) {
    1766             :                 /* Maybe a file ? */
    1767        1808 :                 status = cli_smb2_create_fnum(cli,
    1768             :                         name,
    1769        1808 :                         (struct cli_smb2_create_flags){0},
    1770             :                         SMB2_IMPERSONATION_IMPERSONATION,
    1771             :                         FILE_READ_ATTRIBUTES,           /* desired_access */
    1772             :                         0, /* file attributes */
    1773             :                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
    1774             :                         FILE_OPEN,              /* create_disposition */
    1775             :                         0,      /* create_options */
    1776             :                         NULL,
    1777             :                         &fnum,
    1778             :                         &cr,
    1779             :                         NULL,
    1780             :                         NULL);
    1781             :         }
    1782             : 
    1783        8126 :         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
    1784             :                 /* Maybe a reparse point ? */
    1785           0 :                 status = cli_smb2_create_fnum(cli,
    1786             :                         name,
    1787           0 :                         (struct cli_smb2_create_flags){0},
    1788             :                         SMB2_IMPERSONATION_IMPERSONATION,
    1789             :                         FILE_READ_ATTRIBUTES,           /* desired_access */
    1790             :                         0, /* file attributes */
    1791             :                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
    1792             :                         FILE_OPEN,              /* create_disposition */
    1793             :                         FILE_OPEN_REPARSE_POINT, /* create_options */
    1794             :                         NULL,
    1795             :                         &fnum,
    1796             :                         &cr,
    1797             :                         NULL,
    1798             :                         NULL);
    1799             :         }
    1800             : 
    1801        8126 :         if (!NT_STATUS_IS_OK(status)) {
    1802        4068 :                 return status;
    1803             :         }
    1804             : 
    1805        4058 :         status = cli_smb2_close_fnum(cli, fnum);
    1806             : 
    1807        4058 :         ZERO_STRUCTP(sbuf);
    1808             : 
    1809        4058 :         sbuf->st_ex_atime = nt_time_to_unix_timespec(cr.last_access_time);
    1810        4058 :         sbuf->st_ex_mtime = nt_time_to_unix_timespec(cr.last_write_time);
    1811        4058 :         sbuf->st_ex_ctime = nt_time_to_unix_timespec(cr.change_time);
    1812        4058 :         sbuf->st_ex_size = cr.end_of_file;
    1813        4058 :         *attributes = cr.file_attributes;
    1814             : 
    1815        4058 :         return status;
    1816             : }
    1817             : 
    1818             : struct cli_smb2_query_info_fnum_state {
    1819             :         DATA_BLOB outbuf;
    1820             : };
    1821             : 
    1822             : static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq);
    1823             : 
    1824       11013 : struct tevent_req *cli_smb2_query_info_fnum_send(
    1825             :         TALLOC_CTX *mem_ctx,
    1826             :         struct tevent_context *ev,
    1827             :         struct cli_state *cli,
    1828             :         uint16_t fnum,
    1829             :         uint8_t in_info_type,
    1830             :         uint8_t in_info_class,
    1831             :         uint32_t in_max_output_length,
    1832             :         const DATA_BLOB *in_input_buffer,
    1833             :         uint32_t in_additional_info,
    1834             :         uint32_t in_flags)
    1835             : {
    1836       11013 :         struct tevent_req *req = NULL, *subreq = NULL;
    1837       11013 :         struct cli_smb2_query_info_fnum_state *state = NULL;
    1838       11013 :         struct smb2_hnd *ph = NULL;
    1839           0 :         NTSTATUS status;
    1840             : 
    1841       11013 :         req = tevent_req_create(
    1842             :                 mem_ctx, &state, struct cli_smb2_query_info_fnum_state);
    1843       11013 :         if (req == NULL) {
    1844           0 :                 return req;
    1845             :         }
    1846             : 
    1847       11013 :         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
    1848       11013 :         if (tevent_req_nterror(req, status)) {
    1849           6 :                 return tevent_req_post(req, ev);
    1850             :         }
    1851             : 
    1852       11007 :         subreq = smb2cli_query_info_send(
    1853             :                 state,
    1854             :                 ev,
    1855             :                 cli->conn,
    1856       11007 :                 cli->timeout,
    1857             :                 cli->smb2.session,
    1858             :                 cli->smb2.tcon,
    1859             :                 in_info_type,
    1860             :                 in_info_class,
    1861             :                 in_max_output_length,
    1862             :                 in_input_buffer,
    1863             :                 in_additional_info,
    1864             :                 in_flags,
    1865       11007 :                 ph->fid_persistent,
    1866       11007 :                 ph->fid_volatile);
    1867       11007 :         if (tevent_req_nomem(subreq, req)) {
    1868           0 :                 return tevent_req_post(req, ev);
    1869             :         }
    1870       11007 :         tevent_req_set_callback(subreq, cli_smb2_query_info_fnum_done, req);
    1871       11007 :         return req;
    1872             : }
    1873             : 
    1874       11007 : static void cli_smb2_query_info_fnum_done(struct tevent_req *subreq)
    1875             : {
    1876       11007 :         struct tevent_req *req = tevent_req_callback_data(
    1877             :                 subreq, struct tevent_req);
    1878       11007 :         struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
    1879             :                 req, struct cli_smb2_query_info_fnum_state);
    1880           0 :         DATA_BLOB outbuf;
    1881           0 :         NTSTATUS status;
    1882             : 
    1883       11007 :         status = smb2cli_query_info_recv(subreq, state, &outbuf);
    1884       11007 :         TALLOC_FREE(subreq);
    1885       11007 :         if (tevent_req_nterror(req, status)) {
    1886          39 :                 return;
    1887             :         }
    1888             : 
    1889             :         /*
    1890             :          * We have to dup the memory here because outbuf.data is not
    1891             :          * returned as a talloc object by smb2cli_query_info_recv.
    1892             :          * It's a pointer into the received buffer.
    1893             :          */
    1894       10968 :         state->outbuf = data_blob_dup_talloc(state, outbuf);
    1895             : 
    1896       21816 :         if ((outbuf.length != 0) &&
    1897       10848 :             tevent_req_nomem(state->outbuf.data, req)) {
    1898           0 :                 return;
    1899             :         }
    1900       10968 :         tevent_req_done(req);
    1901             : }
    1902             : 
    1903       11013 : NTSTATUS cli_smb2_query_info_fnum_recv(
    1904             :         struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *outbuf)
    1905             : {
    1906       11013 :         struct cli_smb2_query_info_fnum_state *state = tevent_req_data(
    1907             :                 req, struct cli_smb2_query_info_fnum_state);
    1908           0 :         NTSTATUS status;
    1909             : 
    1910       11013 :         if (tevent_req_is_nterror(req, &status)) {
    1911          45 :                 return status;
    1912             :         }
    1913       10968 :         *outbuf = (DATA_BLOB) {
    1914       10968 :                 .data = talloc_move(mem_ctx, &state->outbuf.data),
    1915       10968 :                 .length = state->outbuf.length,
    1916             :         };
    1917       10968 :         tevent_req_received(req);
    1918       10968 :         return NT_STATUS_OK;
    1919             : }
    1920             : 
    1921        1217 : NTSTATUS cli_smb2_query_info_fnum(
    1922             :         struct cli_state *cli,
    1923             :         uint16_t fnum,
    1924             :         uint8_t in_info_type,
    1925             :         uint8_t in_info_class,
    1926             :         uint32_t in_max_output_length,
    1927             :         const DATA_BLOB *in_input_buffer,
    1928             :         uint32_t in_additional_info,
    1929             :         uint32_t in_flags,
    1930             :         TALLOC_CTX *mem_ctx,
    1931             :         DATA_BLOB *outbuf)
    1932             : {
    1933        1217 :         TALLOC_CTX *frame = talloc_stackframe();
    1934        1217 :         struct tevent_context *ev = NULL;
    1935        1217 :         struct tevent_req *req = NULL;
    1936        1217 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1937           0 :         bool ok;
    1938             : 
    1939        1217 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    1940             :                 /*
    1941             :                  * Can't use sync call while an async call is in flight
    1942             :                  */
    1943           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1944           0 :                 goto fail;
    1945             :         }
    1946        1217 :         ev = samba_tevent_context_init(frame);
    1947        1217 :         if (ev == NULL) {
    1948           0 :                 goto fail;
    1949             :         }
    1950        1217 :         req = cli_smb2_query_info_fnum_send(
    1951             :                 frame,
    1952             :                 ev,
    1953             :                 cli,
    1954             :                 fnum,
    1955             :                 in_info_type,
    1956             :                 in_info_class,
    1957             :                 in_max_output_length,
    1958             :                 in_input_buffer,
    1959             :                 in_additional_info,
    1960             :                 in_flags);
    1961        1217 :         if (req == NULL) {
    1962           0 :                 goto fail;
    1963             :         }
    1964        1217 :         ok = tevent_req_poll_ntstatus(req, ev, &status);
    1965        1217 :         if (!ok) {
    1966           0 :                 goto fail;
    1967             :         }
    1968        1217 :         status = cli_smb2_query_info_fnum_recv(req, mem_ctx, outbuf);
    1969        1217 : fail:
    1970        1217 :         TALLOC_FREE(frame);
    1971        1217 :         return status;
    1972             : }
    1973             : 
    1974             : /***************************************************************
    1975             :  Helper function for pathname operations.
    1976             : ***************************************************************/
    1977             : 
    1978             : struct get_fnum_from_path_state {
    1979             :         struct tevent_context *ev;
    1980             :         struct cli_state *cli;
    1981             :         const char *name;
    1982             :         uint32_t desired_access;
    1983             :         uint16_t fnum;
    1984             : };
    1985             : 
    1986             : static void get_fnum_from_path_opened_file(struct tevent_req *subreq);
    1987             : static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq);
    1988             : static void get_fnum_from_path_opened_dir(struct tevent_req *subreq);
    1989             : 
    1990        6395 : static struct tevent_req *get_fnum_from_path_send(
    1991             :         TALLOC_CTX *mem_ctx,
    1992             :         struct tevent_context *ev,
    1993             :         struct cli_state *cli,
    1994             :         const char *name,
    1995             :         uint32_t desired_access)
    1996             : {
    1997        6395 :         struct tevent_req *req = NULL, *subreq = NULL;
    1998        6395 :         struct get_fnum_from_path_state *state = NULL;
    1999        6395 :         size_t namelen = strlen(name);
    2000             : 
    2001        6395 :         req = tevent_req_create(
    2002             :                 mem_ctx, &state, struct get_fnum_from_path_state);
    2003        6395 :         if (req == NULL) {
    2004           0 :                 return NULL;
    2005             :         }
    2006        6395 :         state->ev = ev;
    2007        6395 :         state->cli = cli;
    2008        6395 :         state->name = name;
    2009        6395 :         state->desired_access = desired_access;
    2010             : 
    2011             :         /*
    2012             :          * SMB2 is pickier about pathnames. Ensure it doesn't end in a
    2013             :          * '\'
    2014             :          */
    2015        6395 :         if (namelen > 0 && name[namelen-1] == '\\') {
    2016         146 :                 state->name = talloc_strndup(state, name, namelen-1);
    2017         146 :                 if (tevent_req_nomem(state->name, req)) {
    2018           0 :                         return tevent_req_post(req, ev);
    2019             :                 }
    2020             :         }
    2021             : 
    2022        6395 :         subreq = cli_smb2_create_fnum_send(
    2023             :                 state,          /* mem_ctx, */
    2024             :                 ev,             /* ev */
    2025             :                 cli,            /* cli */
    2026        6395 :                 state->name, /* fname */
    2027        6395 :                 (struct cli_smb2_create_flags){0}, /* create_flags */
    2028             :                 SMB2_IMPERSONATION_IMPERSONATION, /* impersonation_level */
    2029             :                 desired_access, /* desired_access */
    2030             :                 0,              /* file_attributes */
    2031             :                 FILE_SHARE_READ|
    2032             :                 FILE_SHARE_WRITE|
    2033             :                 FILE_SHARE_DELETE, /* share_access */
    2034             :                 FILE_OPEN,      /* create_disposition */
    2035             :                 0,              /* create_options */
    2036             :                 NULL);          /* in_cblobs */
    2037        6395 :         if (tevent_req_nomem(subreq, req)) {
    2038           0 :                 return tevent_req_post(req, ev);
    2039             :         }
    2040        6395 :         tevent_req_set_callback(subreq, get_fnum_from_path_opened_file, req);
    2041        6395 :         return req;
    2042             : }
    2043             : 
    2044        6395 : static void get_fnum_from_path_opened_file(struct tevent_req *subreq)
    2045             : {
    2046        6395 :         struct tevent_req *req = tevent_req_callback_data(
    2047             :                 subreq, struct tevent_req);
    2048        6395 :         struct get_fnum_from_path_state *state = tevent_req_data(
    2049             :                 req, struct get_fnum_from_path_state);
    2050           0 :         NTSTATUS status;
    2051             : 
    2052        6395 :         status = cli_smb2_create_fnum_recv(
    2053             :                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
    2054        6395 :         TALLOC_FREE(subreq);
    2055             : 
    2056        6395 :         if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) ||
    2057        6395 :             NT_STATUS_EQUAL(status, NT_STATUS_IO_REPARSE_TAG_NOT_HANDLED)) {
    2058             :                 /*
    2059             :                  * Naive option to match our SMB1 code. Assume the
    2060             :                  * symlink path that tripped us up was the last
    2061             :                  * component and try again. Eventually we will have to
    2062             :                  * deal with the returned path unprocessed component. JRA.
    2063             :                  */
    2064           0 :                 subreq = cli_smb2_create_fnum_send(
    2065             :                         state,          /* mem_ctx, */
    2066             :                         state->ev,   /* ev */
    2067             :                         state->cli,  /* cli */
    2068             :                         state->name, /* fname */
    2069           0 :                         (struct cli_smb2_create_flags){0}, /* create_flags */
    2070             :                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
    2071             :                         state->desired_access, /* desired_access */
    2072             :                         0,              /* file_attributes */
    2073             :                         FILE_SHARE_READ|
    2074             :                         FILE_SHARE_WRITE|
    2075             :                         FILE_SHARE_DELETE, /* share_access */
    2076             :                         FILE_OPEN,      /* create_disposition */
    2077             :                         FILE_OPEN_REPARSE_POINT, /* create_options */
    2078             :                         NULL);          /* in_cblobs */
    2079           0 :                 if (tevent_req_nomem(subreq, req)) {
    2080           0 :                         return;
    2081             :                 }
    2082           0 :                 tevent_req_set_callback(
    2083             :                         subreq, get_fnum_from_path_opened_reparse, req);
    2084           0 :                 return;
    2085             :         }
    2086             : 
    2087        6395 :         if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
    2088           0 :                 subreq = cli_smb2_create_fnum_send(
    2089             :                         state,          /* mem_ctx, */
    2090             :                         state->ev,   /* ev */
    2091             :                         state->cli,  /* cli */
    2092             :                         state->name, /* fname */
    2093           0 :                         (struct cli_smb2_create_flags){0}, /* create_flags */
    2094             :                         SMB2_IMPERSONATION_IMPERSONATION, /* impersonation */
    2095             :                         state->desired_access, /* desired_access */
    2096             :                         0,              /* file_attributes */
    2097             :                         FILE_SHARE_READ|
    2098             :                         FILE_SHARE_WRITE|
    2099             :                         FILE_SHARE_DELETE, /* share_access */
    2100             :                         FILE_OPEN,      /* create_disposition */
    2101             :                         FILE_DIRECTORY_FILE, /* create_options */
    2102             :                         NULL);          /* in_cblobs */
    2103           0 :                 if (tevent_req_nomem(subreq, req)) {
    2104           0 :                         return;
    2105             :                 }
    2106           0 :                 tevent_req_set_callback(
    2107             :                         subreq, get_fnum_from_path_opened_dir, req);
    2108           0 :                 return;
    2109             :         }
    2110             : 
    2111        6395 :         if (tevent_req_nterror(req, status)) {
    2112         616 :                 return;
    2113             :         }
    2114        5779 :         tevent_req_done(req);
    2115             : }
    2116             : 
    2117           0 : static void get_fnum_from_path_opened_reparse(struct tevent_req *subreq)
    2118             : {
    2119           0 :         struct tevent_req *req = tevent_req_callback_data(
    2120             :                 subreq, struct tevent_req);
    2121           0 :         struct get_fnum_from_path_state *state = tevent_req_data(
    2122             :                 req, struct get_fnum_from_path_state);
    2123           0 :         NTSTATUS status = cli_smb2_create_fnum_recv(
    2124             :                 subreq, &state->fnum, NULL, NULL, NULL, NULL);
    2125           0 :         tevent_req_simple_finish_ntstatus(subreq, status);
    2126           0 : }
    2127             : 
    2128           0 : static void get_fnum_from_path_opened_dir(struct tevent_req *subreq)
    2129             : {
    2130             :         /* Abstraction violation, but these two are just the same... */
    2131           0 :         get_fnum_from_path_opened_reparse(subreq);
    2132           0 : }
    2133             : 
    2134        6395 : static NTSTATUS get_fnum_from_path_recv(
    2135             :         struct tevent_req *req, uint16_t *pfnum)
    2136             : {
    2137        6395 :         struct get_fnum_from_path_state *state = tevent_req_data(
    2138             :                 req, struct get_fnum_from_path_state);
    2139        6395 :         NTSTATUS status = NT_STATUS_OK;
    2140             : 
    2141        6395 :         if (!tevent_req_is_nterror(req, &status)) {
    2142        5779 :                 *pfnum = state->fnum;
    2143             :         }
    2144        6395 :         tevent_req_received(req);
    2145        6395 :         return status;
    2146             : }
    2147             : 
    2148        1296 : static NTSTATUS get_fnum_from_path(struct cli_state *cli,
    2149             :                                 const char *name,
    2150             :                                 uint32_t desired_access,
    2151             :                                 uint16_t *pfnum)
    2152             : {
    2153        1296 :         TALLOC_CTX *frame = talloc_stackframe();
    2154        1296 :         struct tevent_context *ev = NULL;
    2155        1296 :         struct tevent_req *req = NULL;
    2156        1296 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    2157             : 
    2158        1296 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    2159           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    2160           0 :                 goto fail;
    2161             :         }
    2162        1296 :         ev = samba_tevent_context_init(frame);
    2163        1296 :         if (ev == NULL) {
    2164           0 :                 goto fail;
    2165             :         }
    2166        1296 :         req = get_fnum_from_path_send(frame, ev, cli, name, desired_access);
    2167        1296 :         if (req == NULL) {
    2168           0 :                 goto fail;
    2169             :         }
    2170        1296 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    2171           0 :                 goto fail;
    2172             :         }
    2173        1296 :         status = get_fnum_from_path_recv(req, pfnum);
    2174        1296 :  fail:
    2175        1296 :         TALLOC_FREE(frame);
    2176        1296 :         return status;
    2177             : }
    2178             : 
    2179             : struct cli_smb2_qpathinfo_state {
    2180             :         struct tevent_context *ev;
    2181             :         struct cli_state *cli;
    2182             :         const char *fname;
    2183             :         uint16_t fnum;
    2184             :         uint16_t level;
    2185             :         uint32_t min_rdata;
    2186             :         uint32_t max_rdata;
    2187             : 
    2188             :         NTSTATUS status;
    2189             :         DATA_BLOB out;
    2190             : };
    2191             : 
    2192             : static void cli_smb2_qpathinfo_opened(struct tevent_req *subreq);
    2193             : static void cli_smb2_qpathinfo_done(struct tevent_req *subreq);
    2194             : static void cli_smb2_qpathinfo_closed(struct tevent_req *subreq);
    2195             : 
    2196        4874 : struct tevent_req *cli_smb2_qpathinfo_send(TALLOC_CTX *mem_ctx,
    2197             :                                            struct tevent_context *ev,
    2198             :                                            struct cli_state *cli,
    2199             :                                            const char *fname,
    2200             :                                            uint16_t level,
    2201             :                                            uint32_t min_rdata,
    2202             :                                            uint32_t max_rdata)
    2203             : {
    2204        4874 :         struct tevent_req *req = NULL, *subreq = NULL;
    2205        4874 :         struct cli_smb2_qpathinfo_state *state = NULL;
    2206             : 
    2207        4874 :         req = tevent_req_create(mem_ctx,
    2208             :                                 &state,
    2209             :                                 struct cli_smb2_qpathinfo_state);
    2210        4874 :         if (req == NULL) {
    2211           0 :                 return NULL;
    2212             :         }
    2213        4874 :         state->ev = ev;
    2214        4874 :         state->cli = cli;
    2215        4874 :         state->level = level;
    2216        4874 :         state->min_rdata = min_rdata;
    2217        4874 :         state->max_rdata = max_rdata;
    2218             : 
    2219        4874 :         subreq = get_fnum_from_path_send(state,
    2220             :                                          ev,
    2221             :                                          cli,
    2222             :                                          fname,
    2223             :                                          FILE_READ_ATTRIBUTES);
    2224        4874 :         if (tevent_req_nomem(subreq, req)) {
    2225           0 :                 return tevent_req_post(req, ev);
    2226             :         }
    2227        4874 :         tevent_req_set_callback(subreq, cli_smb2_qpathinfo_opened, req);
    2228        4874 :         return req;
    2229             : }
    2230             : 
    2231        4874 : static void cli_smb2_qpathinfo_opened(struct tevent_req *subreq)
    2232             : {
    2233           0 :         struct tevent_req *req =
    2234        4874 :                 tevent_req_callback_data(subreq, struct tevent_req);
    2235           0 :         struct cli_smb2_qpathinfo_state *state =
    2236        4874 :                 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
    2237           0 :         NTSTATUS status;
    2238             : 
    2239        4874 :         status = get_fnum_from_path_recv(subreq, &state->fnum);
    2240        4874 :         TALLOC_FREE(subreq);
    2241        4874 :         if (tevent_req_nterror(req, status)) {
    2242         611 :                 return;
    2243             :         }
    2244             : 
    2245        4263 :         subreq = cli_smb2_query_info_fnum_send(state,
    2246             :                                                state->ev,
    2247             :                                                state->cli,
    2248        4263 :                                                state->fnum,
    2249             :                                                1, /* in_info_type */
    2250        4263 :                                                state->level,
    2251             :                                                state->max_rdata,
    2252             :                                                NULL, /* in_input_buffer */
    2253             :                                                0,    /* in_additional_info */
    2254             :                                                0);   /* in_flags */
    2255        4263 :         if (tevent_req_nomem(subreq, req)) {
    2256           0 :                 return;
    2257             :         }
    2258        4263 :         tevent_req_set_callback(subreq, cli_smb2_qpathinfo_done, req);
    2259             : }
    2260             : 
    2261        4263 : static void cli_smb2_qpathinfo_done(struct tevent_req *subreq)
    2262             : {
    2263           0 :         struct tevent_req *req =
    2264        4263 :                 tevent_req_callback_data(subreq, struct tevent_req);
    2265           0 :         struct cli_smb2_qpathinfo_state *state =
    2266        4263 :                 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
    2267             : 
    2268           0 :         state->status =
    2269        4263 :                 cli_smb2_query_info_fnum_recv(subreq, state, &state->out);
    2270        4263 :         TALLOC_FREE(subreq);
    2271             : 
    2272        4263 :         if (NT_STATUS_IS_OK(state->status) &&
    2273        4235 :             (state->out.length < state->min_rdata)) {
    2274           0 :                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2275             :         }
    2276             : 
    2277        4263 :         subreq = cli_smb2_close_fnum_send(state,
    2278             :                                           state->ev,
    2279             :                                           state->cli,
    2280        4263 :                                           state->fnum,
    2281             :                                           0);
    2282        4263 :         if (tevent_req_nomem(subreq, req)) {
    2283           0 :                 return;
    2284             :         }
    2285        4263 :         tevent_req_set_callback(subreq, cli_smb2_qpathinfo_closed, req);
    2286             : }
    2287             : 
    2288        4263 : static void cli_smb2_qpathinfo_closed(struct tevent_req *subreq)
    2289             : {
    2290           0 :         struct tevent_req *req =
    2291        4263 :                 tevent_req_callback_data(subreq, struct tevent_req);
    2292           0 :         struct cli_smb2_qpathinfo_state *state =
    2293        4263 :                 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
    2294           0 :         NTSTATUS status;
    2295             : 
    2296        4263 :         status = cli_smb2_close_fnum_recv(subreq);
    2297        4263 :         TALLOC_FREE(subreq);
    2298        4263 :         if (tevent_req_nterror(req, status)) {
    2299          28 :                 return;
    2300             :         }
    2301        4263 :         if (tevent_req_nterror(req, state->status)) {
    2302          28 :                 return;
    2303             :         }
    2304        4235 :         tevent_req_done(req);
    2305             : }
    2306             : 
    2307        4874 : NTSTATUS cli_smb2_qpathinfo_recv(struct tevent_req *req,
    2308             :                                  TALLOC_CTX *mem_ctx,
    2309             :                                  uint8_t **rdata,
    2310             :                                  uint32_t *num_rdata)
    2311             : {
    2312           0 :         struct cli_smb2_qpathinfo_state *state =
    2313        4874 :                 tevent_req_data(req, struct cli_smb2_qpathinfo_state);
    2314           0 :         NTSTATUS status;
    2315             : 
    2316        4874 :         if (tevent_req_is_nterror(req, &status)) {
    2317         639 :                 return status;
    2318             :         }
    2319             : 
    2320        4235 :         *rdata = talloc_move(mem_ctx, &state->out.data);
    2321        4235 :         *num_rdata = state->out.length;
    2322        4235 :         tevent_req_received(req);
    2323        4235 :         return NT_STATUS_OK;
    2324             : }
    2325             : 
    2326             : /***************************************************************
    2327             :  Wrapper that allows SMB2 to set SMB_FILE_BASIC_INFORMATION on
    2328             :  a pathname.
    2329             :  Synchronous only.
    2330             : ***************************************************************/
    2331             : 
    2332        1296 : NTSTATUS cli_smb2_setpathinfo(struct cli_state *cli,
    2333             :                         const char *name,
    2334             :                         uint8_t in_info_type,
    2335             :                         uint8_t in_file_info_class,
    2336             :                         const DATA_BLOB *p_in_data)
    2337             : {
    2338           0 :         NTSTATUS status;
    2339        1296 :         uint16_t fnum = 0xffff;
    2340        1296 :         TALLOC_CTX *frame = talloc_stackframe();
    2341             : 
    2342        1296 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    2343             :                 /*
    2344             :                  * Can't use sync call while an async call is in flight
    2345             :                  */
    2346           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    2347           0 :                 goto fail;
    2348             :         }
    2349             : 
    2350        1296 :         status = get_fnum_from_path(cli,
    2351             :                                 name,
    2352             :                                 FILE_WRITE_ATTRIBUTES,
    2353             :                                 &fnum);
    2354             : 
    2355        1296 :         if (!NT_STATUS_IS_OK(status)) {
    2356           5 :                 goto fail;
    2357             :         }
    2358             : 
    2359        1291 :         status = cli_smb2_set_info_fnum(
    2360             :                 cli,
    2361             :                 fnum,
    2362             :                 in_info_type,
    2363             :                 in_file_info_class,
    2364             :                 p_in_data,         /* in_input_buffer */
    2365             :                 0);                /* in_additional_info */
    2366        1296 :   fail:
    2367             : 
    2368        1296 :         if (fnum != 0xffff) {
    2369        1291 :                 cli_smb2_close_fnum(cli, fnum);
    2370             :         }
    2371             : 
    2372        1296 :         cli->raw_status = status;
    2373             : 
    2374        1296 :         TALLOC_FREE(frame);
    2375        1296 :         return status;
    2376             : }
    2377             : 
    2378             : 
    2379             : /***************************************************************
    2380             :  Wrapper that allows SMB2 to set pathname attributes.
    2381             :  Synchronous only.
    2382             : ***************************************************************/
    2383             : 
    2384        1280 : NTSTATUS cli_smb2_setatr(struct cli_state *cli,
    2385             :                         const char *name,
    2386             :                         uint32_t attr,
    2387             :                         time_t mtime)
    2388             : {
    2389           0 :         uint8_t inbuf_store[40];
    2390        1280 :         DATA_BLOB inbuf = data_blob_null;
    2391             : 
    2392             :         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
    2393             :            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
    2394             : 
    2395        1280 :         inbuf.data = inbuf_store;
    2396        1280 :         inbuf.length = sizeof(inbuf_store);
    2397        1280 :         data_blob_clear(&inbuf);
    2398             : 
    2399             :         /*
    2400             :          * SMB1 uses attr == 0 to clear all attributes
    2401             :          * on a file (end up with FILE_ATTRIBUTE_NORMAL),
    2402             :          * and attr == FILE_ATTRIBUTE_NORMAL to mean ignore
    2403             :          * request attribute change.
    2404             :          *
    2405             :          * SMB2 uses exactly the reverse. Unfortunately as the
    2406             :          * cli_setatr() ABI is exposed inside libsmbclient,
    2407             :          * we must make the SMB2 cli_smb2_setatr() call
    2408             :          * export the same ABI as the SMB1 cli_setatr()
    2409             :          * which calls it. This means reversing the sense
    2410             :          * of the requested attr argument if it's zero
    2411             :          * or FILE_ATTRIBUTE_NORMAL.
    2412             :          *
    2413             :          * See BUG: https://bugzilla.samba.org/show_bug.cgi?id=12899
    2414             :          */
    2415             : 
    2416        1280 :         if (attr == 0) {
    2417         116 :                 attr = FILE_ATTRIBUTE_NORMAL;
    2418        1164 :         } else if (attr == FILE_ATTRIBUTE_NORMAL) {
    2419         676 :                 attr = 0;
    2420             :         }
    2421             : 
    2422        1280 :         SIVAL(inbuf.data, 32, attr);
    2423        1280 :         if (mtime != 0) {
    2424          92 :                 put_long_date((char *)inbuf.data + 16,mtime);
    2425             :         }
    2426             :         /* Set all the other times to -1. */
    2427        1280 :         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
    2428        1280 :         SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL);
    2429        1280 :         SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL);
    2430             : 
    2431        1280 :         return cli_smb2_setpathinfo(
    2432             :                 cli,
    2433             :                 name,
    2434             :                 SMB2_0_INFO_FILE,            /* in_info_type */
    2435             :                 FSCC_FILE_BASIC_INFORMATION, /* in_file_info_class */
    2436             :                 &inbuf);
    2437             : }
    2438             : 
    2439             : 
    2440             : /***************************************************************
    2441             :  Wrapper that allows SMB2 to set file handle times.
    2442             :  Synchronous only.
    2443             : ***************************************************************/
    2444             : 
    2445           0 : NTSTATUS cli_smb2_setattrE(struct cli_state *cli,
    2446             :                         uint16_t fnum,
    2447             :                         time_t change_time,
    2448             :                         time_t access_time,
    2449             :                         time_t write_time)
    2450             : {
    2451           0 :         uint8_t inbuf_store[40];
    2452           0 :         DATA_BLOB inbuf = data_blob_null;
    2453           0 :         NTSTATUS status;
    2454             : 
    2455           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    2456             :                 /*
    2457             :                  * Can't use sync call while an async call is in flight
    2458             :                  */
    2459           0 :                 return NT_STATUS_INVALID_PARAMETER;
    2460             :         }
    2461             : 
    2462             :         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
    2463             :            level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */
    2464             : 
    2465           0 :         inbuf.data = inbuf_store;
    2466           0 :         inbuf.length = sizeof(inbuf_store);
    2467           0 :         data_blob_clear(&inbuf);
    2468             : 
    2469           0 :         SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL);
    2470           0 :         if (change_time != 0) {
    2471           0 :                 put_long_date((char *)inbuf.data + 24, change_time);
    2472             :         }
    2473           0 :         if (access_time != 0) {
    2474           0 :                 put_long_date((char *)inbuf.data + 8, access_time);
    2475             :         }
    2476           0 :         if (write_time != 0) {
    2477           0 :                 put_long_date((char *)inbuf.data + 16, write_time);
    2478             :         }
    2479             : 
    2480           0 :         status = cli_smb2_set_info_fnum(
    2481             :                 cli,
    2482             :                 fnum,
    2483             :                 SMB2_0_INFO_FILE,            /* in_info_type */
    2484             :                 FSCC_FILE_BASIC_INFORMATION, /* in_file_info_class */
    2485             :                 &inbuf,                          /* in_input_buffer */
    2486             :                 0);                          /* in_additional_info */
    2487           0 :         cli->raw_status = status;
    2488           0 :         return status;
    2489             : }
    2490             : 
    2491             : /***************************************************************
    2492             :  Wrapper that allows SMB2 to query disk attributes (size).
    2493             :  Synchronous only.
    2494             : ***************************************************************/
    2495             : 
    2496        1099 : NTSTATUS cli_smb2_dskattr(struct cli_state *cli, const char *path,
    2497             :                           uint64_t *bsize, uint64_t *total, uint64_t *avail)
    2498             : {
    2499           0 :         NTSTATUS status;
    2500        1099 :         uint16_t fnum = 0xffff;
    2501        1099 :         DATA_BLOB outbuf = data_blob_null;
    2502        1099 :         uint32_t sectors_per_unit = 0;
    2503        1099 :         uint32_t bytes_per_sector = 0;
    2504        1099 :         uint64_t total_size = 0;
    2505        1099 :         uint64_t size_free = 0;
    2506        1099 :         TALLOC_CTX *frame = talloc_stackframe();
    2507             : 
    2508        1099 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    2509             :                 /*
    2510             :                  * Can't use sync call while an async call is in flight
    2511             :                  */
    2512           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    2513           0 :                 goto fail;
    2514             :         }
    2515             : 
    2516             :         /* First open the top level directory. */
    2517        1099 :         status = cli_smb2_create_fnum(cli,
    2518             :                         path,
    2519        1099 :                         (struct cli_smb2_create_flags){0},
    2520             :                         SMB2_IMPERSONATION_IMPERSONATION,
    2521             :                         FILE_READ_ATTRIBUTES,   /* desired_access */
    2522             :                         FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
    2523             :                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
    2524             :                         FILE_OPEN,              /* create_disposition */
    2525             :                         FILE_DIRECTORY_FILE,    /* create_options */
    2526             :                         NULL,
    2527             :                         &fnum,
    2528             :                         NULL,
    2529             :                         NULL,
    2530             :                         NULL);
    2531             : 
    2532        1099 :         if (!NT_STATUS_IS_OK(status)) {
    2533           0 :                 goto fail;
    2534             :         }
    2535             : 
    2536             :         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
    2537             :            level 3 (SMB_FS_SIZE_INFORMATION). */
    2538             : 
    2539        1099 :         status = cli_smb2_query_info_fnum(
    2540             :                 cli,
    2541             :                 fnum,
    2542             :                 2, /* in_info_type */
    2543             :                 3, /* in_file_info_class */
    2544             :                 0xFFFF, /* in_max_output_length */
    2545             :                 NULL, /* in_input_buffer */
    2546             :                 0, /* in_additional_info */
    2547             :                 0, /* in_flags */
    2548             :                 frame,
    2549             :                 &outbuf);
    2550        1099 :         if (!NT_STATUS_IS_OK(status)) {
    2551           0 :                 goto fail;
    2552             :         }
    2553             : 
    2554             :         /* Parse the reply. */
    2555        1099 :         if (outbuf.length != 24) {
    2556           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2557           0 :                 goto fail;
    2558             :         }
    2559             : 
    2560        1099 :         total_size = BVAL(outbuf.data, 0);
    2561        1099 :         size_free = BVAL(outbuf.data, 8);
    2562        1099 :         sectors_per_unit = IVAL(outbuf.data, 16);
    2563        1099 :         bytes_per_sector = IVAL(outbuf.data, 20);
    2564             : 
    2565        1099 :         if (bsize) {
    2566        1099 :                 *bsize = (uint64_t)sectors_per_unit * (uint64_t)bytes_per_sector;
    2567             :         }
    2568        1099 :         if (total) {
    2569        1099 :                 *total = total_size;
    2570             :         }
    2571        1099 :         if (avail) {
    2572        1099 :                 *avail = size_free;
    2573             :         }
    2574             : 
    2575        1099 :         status = NT_STATUS_OK;
    2576             : 
    2577        1099 :   fail:
    2578             : 
    2579        1099 :         if (fnum != 0xffff) {
    2580        1099 :                 cli_smb2_close_fnum(cli, fnum);
    2581             :         }
    2582             : 
    2583        1099 :         cli->raw_status = status;
    2584             : 
    2585        1099 :         TALLOC_FREE(frame);
    2586        1099 :         return status;
    2587             : }
    2588             : 
    2589             : /***************************************************************
    2590             :  Wrapper that allows SMB2 to query file system sizes.
    2591             :  Synchronous only.
    2592             : ***************************************************************/
    2593             : 
    2594           0 : NTSTATUS cli_smb2_get_fs_full_size_info(struct cli_state *cli,
    2595             :                                 uint64_t *total_allocation_units,
    2596             :                                 uint64_t *caller_allocation_units,
    2597             :                                 uint64_t *actual_allocation_units,
    2598             :                                 uint64_t *sectors_per_allocation_unit,
    2599             :                                 uint64_t *bytes_per_sector)
    2600             : {
    2601           0 :         NTSTATUS status;
    2602           0 :         uint16_t fnum = 0xffff;
    2603           0 :         DATA_BLOB outbuf = data_blob_null;
    2604           0 :         TALLOC_CTX *frame = talloc_stackframe();
    2605             : 
    2606           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    2607             :                 /*
    2608             :                  * Can't use sync call while an async call is in flight
    2609             :                  */
    2610           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    2611           0 :                 goto fail;
    2612             :         }
    2613             : 
    2614             :         /* First open the top level directory. */
    2615           0 :         status =
    2616           0 :             cli_smb2_create_fnum(cli, "",
    2617           0 :                                  (struct cli_smb2_create_flags){0},
    2618             :                                  SMB2_IMPERSONATION_IMPERSONATION,
    2619             :                                  FILE_READ_ATTRIBUTES,     /* desired_access */
    2620             :                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
    2621             :                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
    2622             :                                      FILE_SHARE_DELETE, /* share_access */
    2623             :                                  FILE_OPEN,             /* create_disposition */
    2624             :                                  FILE_DIRECTORY_FILE,   /* create_options */
    2625             :                                  NULL,
    2626             :                                  &fnum,
    2627             :                                  NULL,
    2628             :                                  NULL,
    2629             :                                  NULL);
    2630             : 
    2631           0 :         if (!NT_STATUS_IS_OK(status)) {
    2632           0 :                 goto fail;
    2633             :         }
    2634             : 
    2635             :         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
    2636             :            level 7 (SMB_FS_FULL_SIZE_INFORMATION). */
    2637             : 
    2638           0 :         status = cli_smb2_query_info_fnum(
    2639             :                 cli,
    2640             :                 fnum,
    2641             :                 SMB2_0_INFO_FILESYSTEM,        /* in_info_type */
    2642             :                 FSCC_FS_FULL_SIZE_INFORMATION, /* in_file_info_class */
    2643             :                 0xFFFF,                        /* in_max_output_length */
    2644             :                 NULL,                          /* in_input_buffer */
    2645             :                 0,                             /* in_additional_info */
    2646             :                 0,                             /* in_flags */
    2647             :                 frame,
    2648             :                 &outbuf);
    2649           0 :         if (!NT_STATUS_IS_OK(status)) {
    2650           0 :                 goto fail;
    2651             :         }
    2652             : 
    2653           0 :         if (outbuf.length < 32) {
    2654           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2655           0 :                 goto fail;
    2656             :         }
    2657             : 
    2658           0 :         *total_allocation_units = BIG_UINT(outbuf.data, 0);
    2659           0 :         *caller_allocation_units = BIG_UINT(outbuf.data, 8);
    2660           0 :         *actual_allocation_units = BIG_UINT(outbuf.data, 16);
    2661           0 :         *sectors_per_allocation_unit = (uint64_t)IVAL(outbuf.data, 24);
    2662           0 :         *bytes_per_sector = (uint64_t)IVAL(outbuf.data, 28);
    2663             : 
    2664           0 : fail:
    2665             : 
    2666           0 :         if (fnum != 0xffff) {
    2667           0 :                 cli_smb2_close_fnum(cli, fnum);
    2668             :         }
    2669             : 
    2670           0 :         cli->raw_status = status;
    2671             : 
    2672           0 :         TALLOC_FREE(frame);
    2673           0 :         return status;
    2674             : }
    2675             : 
    2676             : /***************************************************************
    2677             :  Wrapper that allows SMB2 to query file system attributes.
    2678             :  Synchronous only.
    2679             : ***************************************************************/
    2680             : 
    2681          79 : NTSTATUS cli_smb2_get_fs_attr_info(struct cli_state *cli, uint32_t *fs_attr)
    2682             : {
    2683           0 :         NTSTATUS status;
    2684          79 :         uint16_t fnum = 0xffff;
    2685          79 :         DATA_BLOB outbuf = data_blob_null;
    2686          79 :         TALLOC_CTX *frame = talloc_stackframe();
    2687             : 
    2688          79 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    2689             :                 /*
    2690             :                  * Can't use sync call while an async call is in flight
    2691             :                  */
    2692           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    2693           0 :                 goto fail;
    2694             :         }
    2695             : 
    2696             :         /* First open the top level directory. */
    2697           0 :         status =
    2698          79 :             cli_smb2_create_fnum(cli, "",
    2699          79 :                                  (struct cli_smb2_create_flags){0},
    2700             :                                  SMB2_IMPERSONATION_IMPERSONATION,
    2701             :                                  FILE_READ_ATTRIBUTES,     /* desired_access */
    2702             :                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
    2703             :                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
    2704             :                                      FILE_SHARE_DELETE, /* share_access */
    2705             :                                  FILE_OPEN,             /* create_disposition */
    2706             :                                  FILE_DIRECTORY_FILE,   /* create_options */
    2707             :                                  NULL,
    2708             :                                  &fnum,
    2709             :                                  NULL,
    2710             :                                  NULL,
    2711             :                                  NULL);
    2712             : 
    2713          79 :         if (!NT_STATUS_IS_OK(status)) {
    2714           0 :                 goto fail;
    2715             :         }
    2716             : 
    2717          79 :         status = cli_smb2_query_info_fnum(
    2718             :                 cli,
    2719             :                 fnum,
    2720             :                 2, /* in_info_type */
    2721             :                 5,                     /* in_file_info_class */
    2722             :                 0xFFFF, /* in_max_output_length */
    2723             :                 NULL,   /* in_input_buffer */
    2724             :                 0,      /* in_additional_info */
    2725             :                 0,      /* in_flags */
    2726             :                 frame,
    2727             :                 &outbuf);
    2728          79 :         if (!NT_STATUS_IS_OK(status)) {
    2729           0 :                 goto fail;
    2730             :         }
    2731             : 
    2732          79 :         if (outbuf.length < 12) {
    2733           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2734           0 :                 goto fail;
    2735             :         }
    2736             : 
    2737          79 :         *fs_attr = IVAL(outbuf.data, 0);
    2738             : 
    2739          79 : fail:
    2740             : 
    2741          79 :         if (fnum != 0xffff) {
    2742          79 :                 cli_smb2_close_fnum(cli, fnum);
    2743             :         }
    2744             : 
    2745          79 :         cli->raw_status = status;
    2746             : 
    2747          79 :         TALLOC_FREE(frame);
    2748          79 :         return status;
    2749             : }
    2750             : 
    2751             : /***************************************************************
    2752             :  Wrapper that allows SMB2 to query file system volume info.
    2753             :  Synchronous only.
    2754             : ***************************************************************/
    2755             : 
    2756          16 : NTSTATUS cli_smb2_get_fs_volume_info(struct cli_state *cli,
    2757             :                                 TALLOC_CTX *mem_ctx,
    2758             :                                 char **_volume_name,
    2759             :                                 uint32_t *pserial_number,
    2760             :                                 time_t *pdate)
    2761             : {
    2762           0 :         NTSTATUS status;
    2763          16 :         uint16_t fnum = 0xffff;
    2764          16 :         DATA_BLOB outbuf = data_blob_null;
    2765           0 :         uint32_t nlen;
    2766          16 :         char *volume_name = NULL;
    2767          16 :         TALLOC_CTX *frame = talloc_stackframe();
    2768             : 
    2769          16 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    2770             :                 /*
    2771             :                  * Can't use sync call while an async call is in flight
    2772             :                  */
    2773           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    2774           0 :                 goto fail;
    2775             :         }
    2776             : 
    2777             :         /* First open the top level directory. */
    2778           0 :         status =
    2779          16 :             cli_smb2_create_fnum(cli, "",
    2780          16 :                                  (struct cli_smb2_create_flags){0},
    2781             :                                  SMB2_IMPERSONATION_IMPERSONATION,
    2782             :                                  FILE_READ_ATTRIBUTES,     /* desired_access */
    2783             :                                  FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
    2784             :                                  FILE_SHARE_READ | FILE_SHARE_WRITE |
    2785             :                                      FILE_SHARE_DELETE, /* share_access */
    2786             :                                  FILE_OPEN,             /* create_disposition */
    2787             :                                  FILE_DIRECTORY_FILE,   /* create_options */
    2788             :                                  NULL,
    2789             :                                  &fnum,
    2790             :                                  NULL,
    2791             :                                  NULL,
    2792             :                                  NULL);
    2793             : 
    2794          16 :         if (!NT_STATUS_IS_OK(status)) {
    2795           0 :                 goto fail;
    2796             :         }
    2797             : 
    2798             :         /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2),
    2799             :            level 1 (SMB_FS_VOLUME_INFORMATION). */
    2800             : 
    2801          16 :         status = cli_smb2_query_info_fnum(
    2802             :                 cli,
    2803             :                 fnum,
    2804             :                 SMB2_0_INFO_FILESYSTEM, /* in_info_type */
    2805             :                 /* in_file_info_class */
    2806             :                 FSCC_FS_VOLUME_INFORMATION,
    2807             :                 0xFFFF, /* in_max_output_length */
    2808             :                 NULL,   /* in_input_buffer */
    2809             :                 0,      /* in_additional_info */
    2810             :                 0,      /* in_flags */
    2811             :                 frame,
    2812             :                 &outbuf);
    2813          16 :         if (!NT_STATUS_IS_OK(status)) {
    2814           0 :                 goto fail;
    2815             :         }
    2816             : 
    2817          16 :         if (outbuf.length < 24) {
    2818           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2819           0 :                 goto fail;
    2820             :         }
    2821             : 
    2822          16 :         if (pdate) {
    2823           0 :                 struct timespec ts;
    2824          16 :                 ts = interpret_long_date(BVAL(outbuf.data, 0));
    2825          16 :                 *pdate = ts.tv_sec;
    2826             :         }
    2827          16 :         if (pserial_number) {
    2828          16 :                 *pserial_number = IVAL(outbuf.data,8);
    2829             :         }
    2830          16 :         nlen = IVAL(outbuf.data,12);
    2831          16 :         if (nlen + 18 < 18) {
    2832             :                 /* Integer wrap. */
    2833           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2834           0 :                 goto fail;
    2835             :         }
    2836             :         /*
    2837             :          * The next check is safe as we know outbuf.length >= 24
    2838             :          * from above.
    2839             :          */
    2840          16 :         if (nlen > (outbuf.length - 18)) {
    2841           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2842           0 :                 goto fail;
    2843             :         }
    2844             : 
    2845          16 :         pull_string_talloc(mem_ctx,
    2846          16 :                            (const char *)outbuf.data,
    2847             :                            0,
    2848             :                            &volume_name,
    2849          16 :                            outbuf.data + 18,
    2850             :                            nlen,
    2851             :                            STR_UNICODE);
    2852          16 :         if (volume_name == NULL) {
    2853           0 :                 status = map_nt_error_from_unix(errno);
    2854           0 :                 goto fail;
    2855             :         }
    2856             : 
    2857          16 :         *_volume_name = volume_name;
    2858             : 
    2859          16 : fail:
    2860             : 
    2861          16 :         if (fnum != 0xffff) {
    2862          16 :                 cli_smb2_close_fnum(cli, fnum);
    2863             :         }
    2864             : 
    2865          16 :         cli->raw_status = status;
    2866             : 
    2867          16 :         TALLOC_FREE(frame);
    2868          16 :         return status;
    2869             : }
    2870             : 
    2871             : struct cli_smb2_mxac_state {
    2872             :         struct tevent_context *ev;
    2873             :         struct cli_state *cli;
    2874             :         const char *fname;
    2875             :         struct smb2_create_blobs in_cblobs;
    2876             :         uint16_t fnum;
    2877             :         NTSTATUS status;
    2878             :         uint32_t mxac;
    2879             : };
    2880             : 
    2881             : static void cli_smb2_mxac_opened(struct tevent_req *subreq);
    2882             : static void cli_smb2_mxac_closed(struct tevent_req *subreq);
    2883             : 
    2884           4 : struct tevent_req *cli_smb2_query_mxac_send(TALLOC_CTX *mem_ctx,
    2885             :                                             struct tevent_context *ev,
    2886             :                                             struct cli_state *cli,
    2887             :                                             const char *fname)
    2888             : {
    2889           4 :         struct tevent_req *req = NULL, *subreq = NULL;
    2890           4 :         struct cli_smb2_mxac_state *state = NULL;
    2891           0 :         NTSTATUS status;
    2892             : 
    2893           4 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_mxac_state);
    2894           4 :         if (req == NULL) {
    2895           0 :                 return NULL;
    2896             :         }
    2897           4 :         *state = (struct cli_smb2_mxac_state) {
    2898             :                 .ev = ev,
    2899             :                 .cli = cli,
    2900             :                 .fname = fname,
    2901             :         };
    2902             : 
    2903           4 :         status = smb2_create_blob_add(state,
    2904           4 :                                       &state->in_cblobs,
    2905             :                                       SMB2_CREATE_TAG_MXAC,
    2906             :                                       data_blob(NULL, 0));
    2907           4 :         if (tevent_req_nterror(req, status)) {
    2908           0 :                 return tevent_req_post(req, ev);
    2909             :         }
    2910             : 
    2911           4 :         subreq = cli_smb2_create_fnum_send(
    2912             :                 state,
    2913           4 :                 state->ev,
    2914           4 :                 state->cli,
    2915           4 :                 state->fname,
    2916           4 :                 (struct cli_smb2_create_flags){0},
    2917             :                 SMB2_IMPERSONATION_IMPERSONATION,
    2918             :                 FILE_READ_ATTRIBUTES,
    2919             :                 0,                      /* file attributes */
    2920             :                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
    2921             :                 FILE_OPEN,
    2922             :                 0,                      /* create_options */
    2923           4 :                 &state->in_cblobs);
    2924           4 :         if (tevent_req_nomem(subreq, req)) {
    2925           0 :                 return tevent_req_post(req, ev);
    2926             :         }
    2927           4 :         tevent_req_set_callback(subreq, cli_smb2_mxac_opened, req);
    2928           4 :         return req;
    2929             : }
    2930             : 
    2931           4 : static void cli_smb2_mxac_opened(struct tevent_req *subreq)
    2932             : {
    2933           4 :         struct tevent_req *req = tevent_req_callback_data(
    2934             :                 subreq, struct tevent_req);
    2935           4 :         struct cli_smb2_mxac_state *state = tevent_req_data(
    2936             :                 req, struct cli_smb2_mxac_state);
    2937           4 :         struct smb2_create_blobs out_cblobs = {0};
    2938           4 :         struct smb2_create_blob *mxac_blob = NULL;
    2939           0 :         NTSTATUS status;
    2940             : 
    2941           4 :         status = cli_smb2_create_fnum_recv(
    2942             :                 subreq, &state->fnum, NULL, state, &out_cblobs, NULL);
    2943           4 :         TALLOC_FREE(subreq);
    2944             : 
    2945           4 :         if (tevent_req_nterror(req, status)) {
    2946           0 :                 return;
    2947             :         }
    2948             : 
    2949           4 :         mxac_blob = smb2_create_blob_find(&out_cblobs, SMB2_CREATE_TAG_MXAC);
    2950           4 :         if (mxac_blob == NULL) {
    2951           0 :                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2952           0 :                 goto close;
    2953             :         }
    2954           4 :         if (mxac_blob->data.length != 8) {
    2955           0 :                 state->status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    2956           0 :                 goto close;
    2957             :         }
    2958             : 
    2959           4 :         state->status = NT_STATUS(IVAL(mxac_blob->data.data, 0));
    2960           4 :         state->mxac = IVAL(mxac_blob->data.data, 4);
    2961             : 
    2962           4 : close:
    2963           4 :         subreq = cli_smb2_close_fnum_send(state,
    2964             :                                           state->ev,
    2965             :                                           state->cli,
    2966           4 :                                           state->fnum,
    2967             :                                           0);
    2968           4 :         if (tevent_req_nomem(subreq, req)) {
    2969           0 :                 return;
    2970             :         }
    2971           4 :         tevent_req_set_callback(subreq, cli_smb2_mxac_closed, req);
    2972             : 
    2973           4 :         return;
    2974             : }
    2975             : 
    2976           4 : static void cli_smb2_mxac_closed(struct tevent_req *subreq)
    2977             : {
    2978           4 :         struct tevent_req *req = tevent_req_callback_data(
    2979             :                 subreq, struct tevent_req);
    2980           0 :         NTSTATUS status;
    2981             : 
    2982           4 :         status = cli_smb2_close_fnum_recv(subreq);
    2983           4 :         if (tevent_req_nterror(req, status)) {
    2984           0 :                 return;
    2985             :         }
    2986             : 
    2987           4 :         tevent_req_done(req);
    2988             : }
    2989             : 
    2990           4 : NTSTATUS cli_smb2_query_mxac_recv(struct tevent_req *req, uint32_t *mxac)
    2991             : {
    2992           4 :         struct cli_smb2_mxac_state *state = tevent_req_data(
    2993             :                 req, struct cli_smb2_mxac_state);
    2994           0 :         NTSTATUS status;
    2995             : 
    2996           4 :         if (tevent_req_is_nterror(req, &status)) {
    2997           0 :                 return status;
    2998             :         }
    2999             : 
    3000           4 :         if (!NT_STATUS_IS_OK(state->status)) {
    3001           0 :                 return state->status;
    3002             :         }
    3003             : 
    3004           4 :         *mxac = state->mxac;
    3005           4 :         return NT_STATUS_OK;
    3006             : }
    3007             : 
    3008           4 : NTSTATUS cli_smb2_query_mxac(struct cli_state *cli,
    3009             :                              const char *fname,
    3010             :                              uint32_t *_mxac)
    3011             : {
    3012           4 :         TALLOC_CTX *frame = talloc_stackframe();
    3013           4 :         struct tevent_context *ev = NULL;
    3014           4 :         struct tevent_req *req = NULL;
    3015           4 :         NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
    3016           0 :         bool ok;
    3017             : 
    3018           4 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3019             :                 /*
    3020             :                  * Can't use sync call while an async call is in flight
    3021             :                  */
    3022           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3023           0 :                 goto fail;
    3024             :         }
    3025             : 
    3026           4 :         ev = samba_tevent_context_init(frame);
    3027           4 :         if (ev == NULL) {
    3028           0 :                 goto fail;
    3029             :         }
    3030           4 :         req = cli_smb2_query_mxac_send(frame, ev, cli, fname);
    3031           4 :         if (req == NULL) {
    3032           0 :                 goto fail;
    3033             :         }
    3034           4 :         ok = tevent_req_poll_ntstatus(req, ev, &status);
    3035           4 :         if (!ok) {
    3036           0 :                 goto fail;
    3037             :         }
    3038           4 :         status = cli_smb2_query_mxac_recv(req, _mxac);
    3039             : 
    3040           4 : fail:
    3041           4 :         cli->raw_status = status;
    3042           4 :         TALLOC_FREE(frame);
    3043           4 :         return status;
    3044             : }
    3045             : 
    3046             : struct cli_smb2_rename_fnum_state {
    3047             :         DATA_BLOB inbuf;
    3048             : };
    3049             : 
    3050             : static void cli_smb2_rename_fnum_done(struct tevent_req *subreq);
    3051             : 
    3052         225 : static struct tevent_req *cli_smb2_rename_fnum_send(
    3053             :         TALLOC_CTX *mem_ctx,
    3054             :         struct tevent_context *ev,
    3055             :         struct cli_state *cli,
    3056             :         uint16_t fnum,
    3057             :         const char *fname_dst,
    3058             :         bool replace)
    3059             : {
    3060         225 :         struct tevent_req *req = NULL, *subreq = NULL;
    3061         225 :         struct cli_smb2_rename_fnum_state *state = NULL;
    3062         225 :         size_t namelen = strlen(fname_dst);
    3063         225 :         smb_ucs2_t *converted_str = NULL;
    3064         225 :         size_t converted_size_bytes = 0;
    3065           0 :         size_t inbuf_size;
    3066           0 :         bool ok;
    3067             : 
    3068         225 :         req = tevent_req_create(
    3069             :                 mem_ctx, &state, struct cli_smb2_rename_fnum_state);
    3070         225 :         if (req == NULL) {
    3071           0 :                 return NULL;
    3072             :         }
    3073             : 
    3074             :         /*
    3075             :          * SMB2 is pickier about pathnames. Ensure it doesn't start in
    3076             :          * a '\'
    3077             :          */
    3078         225 :         if (*fname_dst == '\\') {
    3079         181 :                 fname_dst++;
    3080             :         }
    3081             : 
    3082             :         /*
    3083             :          * SMB2 is pickier about pathnames. Ensure it doesn't end in a
    3084             :          * '\'
    3085             :          */
    3086         225 :         if (namelen > 0 && fname_dst[namelen-1] == '\\') {
    3087           0 :                 fname_dst = talloc_strndup(state, fname_dst, namelen-1);
    3088           0 :                 if (tevent_req_nomem(fname_dst, req)) {
    3089           0 :                         return tevent_req_post(req, ev);
    3090             :                 }
    3091             :         }
    3092             : 
    3093         225 :         ok = push_ucs2_talloc(
    3094             :                 state, &converted_str, fname_dst, &converted_size_bytes);
    3095         225 :         if (!ok) {
    3096           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    3097           0 :                 return tevent_req_post(req, ev);
    3098             :         }
    3099             : 
    3100             :         /*
    3101             :          * W2K8 insists the dest name is not null terminated. Remove
    3102             :          * the last 2 zero bytes and reduce the name length.
    3103             :          */
    3104         225 :         if (converted_size_bytes < 2) {
    3105           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    3106           0 :                 return tevent_req_post(req, ev);
    3107             :         }
    3108         225 :         converted_size_bytes -= 2;
    3109             : 
    3110         225 :         inbuf_size = 20 + converted_size_bytes;
    3111         225 :         if (inbuf_size < 20) {
    3112             :                 /* Integer wrap check. */
    3113           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
    3114           0 :                 return tevent_req_post(req, ev);
    3115             :         }
    3116             : 
    3117             :         /*
    3118             :          * The Windows 10 SMB2 server has a minimum length
    3119             :          * for a SMB2_FILE_RENAME_INFORMATION buffer of
    3120             :          * 24 bytes. It returns NT_STATUS_INFO_LENGTH_MISMATCH
    3121             :          * if the length is less. This isn't an alignment
    3122             :          * issue as Windows client accepts happily 2-byte align
    3123             :          * for larger target name sizes. Also the Windows 10
    3124             :          * SMB1 server doesn't have this restriction.
    3125             :          *
    3126             :          * BUG: https://bugzilla.samba.org/show_bug.cgi?id=14403
    3127             :          */
    3128         225 :         inbuf_size = MAX(inbuf_size, 24);
    3129             : 
    3130         225 :         state->inbuf = data_blob_talloc_zero(state, inbuf_size);
    3131         225 :         if (tevent_req_nomem(state->inbuf.data, req)) {
    3132           0 :                 return tevent_req_post(req, ev);
    3133             :         }
    3134             : 
    3135         225 :         if (replace) {
    3136          14 :                 SCVAL(state->inbuf.data, 0, 1);
    3137             :         }
    3138             : 
    3139         225 :         SIVAL(state->inbuf.data, 16, converted_size_bytes);
    3140         225 :         memcpy(state->inbuf.data + 20, converted_str, converted_size_bytes);
    3141             : 
    3142         225 :         TALLOC_FREE(converted_str);
    3143             : 
    3144             :         /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1),
    3145             :            level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */
    3146             : 
    3147         225 :         subreq = cli_smb2_set_info_fnum_send(
    3148             :                 state,                        /* mem_ctx */
    3149             :                 ev,                           /* ev */
    3150             :                 cli,                          /* cli */
    3151             :                 fnum,                         /* fnum */
    3152             :                 SMB2_0_INFO_FILE,             /* in_info_type */
    3153             :                 FSCC_FILE_RENAME_INFORMATION, /* in_file_info_class */
    3154         225 :                 &state->inbuf,                 /* in_input_buffer */
    3155             :                 0);                           /* in_additional_info */
    3156         225 :         if (tevent_req_nomem(subreq, req)) {
    3157           0 :                 return tevent_req_post(req, ev);
    3158             :         }
    3159         225 :         tevent_req_set_callback(subreq, cli_smb2_rename_fnum_done, req);
    3160         225 :         return req;
    3161             : }
    3162             : 
    3163         225 : static void cli_smb2_rename_fnum_done(struct tevent_req *subreq)
    3164             : {
    3165         225 :         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
    3166         225 :         tevent_req_simple_finish_ntstatus(subreq, status);
    3167         225 : }
    3168             : 
    3169         225 : static NTSTATUS cli_smb2_rename_fnum_recv(struct tevent_req *req)
    3170             : {
    3171         225 :         return tevent_req_simple_recv_ntstatus(req);
    3172             : }
    3173             : 
    3174             : /***************************************************************
    3175             :  Wrapper that allows SMB2 to rename a file.
    3176             : ***************************************************************/
    3177             : 
    3178             : struct cli_smb2_rename_state {
    3179             :         struct tevent_context *ev;
    3180             :         struct cli_state *cli;
    3181             :         const char *fname_dst;
    3182             :         bool replace;
    3183             :         uint16_t fnum;
    3184             : 
    3185             :         NTSTATUS rename_status;
    3186             : };
    3187             : 
    3188             : static void cli_smb2_rename_opened(struct tevent_req *subreq);
    3189             : static void cli_smb2_rename_renamed(struct tevent_req *subreq);
    3190             : static void cli_smb2_rename_closed(struct tevent_req *subreq);
    3191             : 
    3192         225 : struct tevent_req *cli_smb2_rename_send(
    3193             :         TALLOC_CTX *mem_ctx,
    3194             :         struct tevent_context *ev,
    3195             :         struct cli_state *cli,
    3196             :         const char *fname_src,
    3197             :         const char *fname_dst,
    3198             :         bool replace)
    3199             : {
    3200         225 :         struct tevent_req *req = NULL, *subreq = NULL;
    3201         225 :         struct cli_smb2_rename_state *state = NULL;
    3202           0 :         NTSTATUS status;
    3203             : 
    3204         225 :         req = tevent_req_create(
    3205             :                 mem_ctx, &state, struct cli_smb2_rename_state);
    3206         225 :         if (req == NULL) {
    3207           0 :                 return NULL;
    3208             :         }
    3209             : 
    3210             :         /*
    3211             :          * Strip a MSDFS path from fname_dst if we were given one.
    3212             :          */
    3213         225 :         status = cli_dfs_target_check(state,
    3214             :                                 cli,
    3215             :                                 fname_dst,
    3216             :                                 &fname_dst);
    3217         225 :         if (tevent_req_nterror(req, status)) {
    3218           0 :                 return tevent_req_post(req, ev);
    3219             :         }
    3220             : 
    3221         225 :         state->ev = ev;
    3222         225 :         state->cli = cli;
    3223         225 :         state->fname_dst = fname_dst;
    3224         225 :         state->replace = replace;
    3225             : 
    3226         225 :         subreq = get_fnum_from_path_send(
    3227             :                 state, ev, cli, fname_src, DELETE_ACCESS);
    3228         225 :         if (tevent_req_nomem(subreq, req)) {
    3229           0 :                 return tevent_req_post(req, ev);
    3230             :         }
    3231         225 :         tevent_req_set_callback(subreq, cli_smb2_rename_opened, req);
    3232         225 :         return req;
    3233             : }
    3234             : 
    3235         225 : static void cli_smb2_rename_opened(struct tevent_req *subreq)
    3236             : {
    3237         225 :         struct tevent_req *req = tevent_req_callback_data(
    3238             :                 subreq, struct tevent_req);
    3239         225 :         struct cli_smb2_rename_state *state = tevent_req_data(
    3240             :                 req, struct cli_smb2_rename_state);
    3241           0 :         NTSTATUS status;
    3242             : 
    3243         225 :         status = get_fnum_from_path_recv(subreq, &state->fnum);
    3244         225 :         TALLOC_FREE(subreq);
    3245         225 :         if (tevent_req_nterror(req, status)) {
    3246           0 :                 return;
    3247             :         }
    3248             : 
    3249         225 :         subreq = cli_smb2_rename_fnum_send(
    3250             :                 state,
    3251             :                 state->ev,
    3252             :                 state->cli,
    3253         225 :                 state->fnum,
    3254             :                 state->fname_dst,
    3255         225 :                 state->replace);
    3256         225 :         if (tevent_req_nomem(subreq, req)) {
    3257           0 :                 return;
    3258             :         }
    3259         225 :         tevent_req_set_callback(subreq, cli_smb2_rename_renamed, req);
    3260             : }
    3261             : 
    3262         225 : static void cli_smb2_rename_renamed(struct tevent_req *subreq)
    3263             : {
    3264         225 :         struct tevent_req *req = tevent_req_callback_data(
    3265             :                 subreq, struct tevent_req);
    3266         225 :         struct cli_smb2_rename_state *state = tevent_req_data(
    3267             :                 req, struct cli_smb2_rename_state);
    3268             : 
    3269         225 :         state->rename_status = cli_smb2_rename_fnum_recv(subreq);
    3270         225 :         TALLOC_FREE(subreq);
    3271             : 
    3272         225 :         subreq = cli_smb2_close_fnum_send(state,
    3273             :                                           state->ev,
    3274             :                                           state->cli,
    3275         225 :                                           state->fnum,
    3276             :                                           0);
    3277         225 :         if (tevent_req_nomem(subreq, req)) {
    3278           0 :                 return;
    3279             :         }
    3280         225 :         tevent_req_set_callback(subreq, cli_smb2_rename_closed, req);
    3281             : }
    3282             : 
    3283         225 : static void cli_smb2_rename_closed(struct tevent_req *subreq)
    3284             : {
    3285         225 :         NTSTATUS status = cli_smb2_close_fnum_recv(subreq);
    3286         225 :         tevent_req_simple_finish_ntstatus(subreq, status);
    3287         225 : }
    3288             : 
    3289         225 : NTSTATUS cli_smb2_rename_recv(struct tevent_req *req)
    3290             : {
    3291         225 :         struct cli_smb2_rename_state *state = tevent_req_data(
    3292             :                 req, struct cli_smb2_rename_state);
    3293         225 :         NTSTATUS status = NT_STATUS_OK;
    3294             : 
    3295         225 :         if (!tevent_req_is_nterror(req, &status)) {
    3296         225 :                 status = state->rename_status;
    3297             :         }
    3298         225 :         tevent_req_received(req);
    3299         225 :         return status;
    3300             : }
    3301             : 
    3302             : /***************************************************************
    3303             :  Wrapper that allows SMB2 to set an EA on a fnum.
    3304             :  Synchronous only.
    3305             : ***************************************************************/
    3306             : 
    3307           0 : NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli,
    3308             :                         uint16_t fnum,
    3309             :                         const char *ea_name,
    3310             :                         const char *ea_val,
    3311             :                         size_t ea_len)
    3312             : {
    3313           0 :         NTSTATUS status;
    3314           0 :         DATA_BLOB inbuf = data_blob_null;
    3315           0 :         size_t bloblen = 0;
    3316           0 :         char *ea_name_ascii = NULL;
    3317           0 :         size_t namelen = 0;
    3318           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3319             : 
    3320           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3321             :                 /*
    3322             :                  * Can't use sync call while an async call is in flight
    3323             :                  */
    3324           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3325           0 :                 goto fail;
    3326             :         }
    3327             : 
    3328             :         /* Marshall the SMB2 EA data. */
    3329           0 :         if (ea_len > 0xFFFF) {
    3330           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3331           0 :                 goto fail;
    3332             :         }
    3333             : 
    3334           0 :         if (!push_ascii_talloc(frame,
    3335             :                                 &ea_name_ascii,
    3336             :                                 ea_name,
    3337             :                                 &namelen)) {
    3338           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3339           0 :                 goto fail;
    3340             :         }
    3341             : 
    3342           0 :         if (namelen < 2 || namelen > 0xFF) {
    3343           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3344           0 :                 goto fail;
    3345             :         }
    3346             : 
    3347           0 :         bloblen = 8 + ea_len + namelen;
    3348             :         /* Round up to a 4 byte boundary. */
    3349           0 :         bloblen = ((bloblen + 3)&~3);
    3350             : 
    3351           0 :         inbuf = data_blob_talloc_zero(frame, bloblen);
    3352           0 :         if (inbuf.data == NULL) {
    3353           0 :                 status = NT_STATUS_NO_MEMORY;
    3354           0 :                 goto fail;
    3355             :         }
    3356             :         /* namelen doesn't include the NULL byte. */
    3357           0 :         SCVAL(inbuf.data, 5, namelen - 1);
    3358           0 :         SSVAL(inbuf.data, 6, ea_len);
    3359           0 :         memcpy(inbuf.data + 8, ea_name_ascii, namelen);
    3360           0 :         memcpy(inbuf.data + 8 + namelen, ea_val, ea_len);
    3361             : 
    3362             :         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
    3363             :            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
    3364             : 
    3365           0 :         status = cli_smb2_set_info_fnum(
    3366             :                 cli,
    3367             :                 fnum,
    3368             :                 SMB2_0_INFO_FILE,              /* in_info_type */
    3369             :                 FSCC_FILE_FULL_EA_INFORMATION, /* in_file_info_class */
    3370             :                 &inbuf,                            /* in_input_buffer */
    3371             :                 0);                            /* in_additional_info */
    3372             : 
    3373           0 :   fail:
    3374             : 
    3375           0 :         cli->raw_status = status;
    3376             : 
    3377           0 :         TALLOC_FREE(frame);
    3378           0 :         return status;
    3379             : }
    3380             : 
    3381             : /***************************************************************
    3382             :  Wrapper that allows SMB2 to set an EA on a pathname.
    3383             :  Synchronous only.
    3384             : ***************************************************************/
    3385             : 
    3386           0 : NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli,
    3387             :                         const char *name,
    3388             :                         const char *ea_name,
    3389             :                         const char *ea_val,
    3390             :                         size_t ea_len)
    3391             : {
    3392           0 :         NTSTATUS status;
    3393           0 :         uint16_t fnum = 0xffff;
    3394             : 
    3395           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3396             :                 /*
    3397             :                  * Can't use sync call while an async call is in flight
    3398             :                  */
    3399           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3400           0 :                 goto fail;
    3401             :         }
    3402             : 
    3403           0 :         status = get_fnum_from_path(cli,
    3404             :                                 name,
    3405             :                                 FILE_WRITE_EA,
    3406             :                                 &fnum);
    3407             : 
    3408           0 :         if (!NT_STATUS_IS_OK(status)) {
    3409           0 :                 goto fail;
    3410             :         }
    3411             : 
    3412           0 :         status = cli_set_ea_fnum(cli,
    3413             :                                 fnum,
    3414             :                                 ea_name,
    3415             :                                 ea_val,
    3416             :                                 ea_len);
    3417           0 :         if (!NT_STATUS_IS_OK(status)) {
    3418           0 :                 goto fail;
    3419             :         }
    3420             : 
    3421           0 :   fail:
    3422             : 
    3423           0 :         if (fnum != 0xffff) {
    3424           0 :                 cli_smb2_close_fnum(cli, fnum);
    3425             :         }
    3426             : 
    3427           0 :         cli->raw_status = status;
    3428             : 
    3429           0 :         return status;
    3430             : }
    3431             : 
    3432             : /***************************************************************
    3433             :  Wrapper that allows SMB2 to get an EA list on a pathname.
    3434             :  Synchronous only.
    3435             : ***************************************************************/
    3436             : 
    3437           0 : NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli,
    3438             :                                 const char *name,
    3439             :                                 TALLOC_CTX *ctx,
    3440             :                                 size_t *pnum_eas,
    3441             :                                 struct ea_struct **pea_array)
    3442             : {
    3443           0 :         NTSTATUS status;
    3444           0 :         uint16_t fnum = 0xffff;
    3445           0 :         DATA_BLOB outbuf = data_blob_null;
    3446           0 :         struct ea_list *ea_list = NULL;
    3447           0 :         struct ea_list *eal = NULL;
    3448           0 :         size_t ea_count = 0;
    3449           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3450             : 
    3451           0 :         *pnum_eas = 0;
    3452           0 :         *pea_array = NULL;
    3453             : 
    3454           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3455             :                 /*
    3456             :                  * Can't use sync call while an async call is in flight
    3457             :                  */
    3458           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3459           0 :                 goto fail;
    3460             :         }
    3461             : 
    3462           0 :         status = get_fnum_from_path(cli,
    3463             :                                 name,
    3464             :                                 FILE_READ_EA,
    3465             :                                 &fnum);
    3466             : 
    3467           0 :         if (!NT_STATUS_IS_OK(status)) {
    3468           0 :                 goto fail;
    3469             :         }
    3470             : 
    3471             :         /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1),
    3472             :            level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */
    3473             : 
    3474           0 :         status = cli_smb2_query_info_fnum(
    3475             :                 cli,
    3476             :                 fnum,
    3477             :                 SMB2_0_INFO_FILE,              /* in_info_type */
    3478             :                 FSCC_FILE_FULL_EA_INFORMATION, /* in_file_info_class */
    3479             :                 0xFFFF,                        /* in_max_output_length */
    3480             :                 NULL,                          /* in_input_buffer */
    3481             :                 0,                             /* in_additional_info */
    3482             :                 0,                             /* in_flags */
    3483             :                 frame,
    3484             :                 &outbuf);
    3485             : 
    3486           0 :         if (!NT_STATUS_IS_OK(status)) {
    3487           0 :                 goto fail;
    3488             :         }
    3489             : 
    3490             :         /* Parse the reply. */
    3491           0 :         ea_list = read_nttrans_ea_list(ctx,
    3492           0 :                                 (const char *)outbuf.data,
    3493             :                                 outbuf.length);
    3494           0 :         if (ea_list == NULL) {
    3495           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    3496           0 :                 goto fail;
    3497             :         }
    3498             : 
    3499             :         /* Convert to an array. */
    3500           0 :         for (eal = ea_list; eal; eal = eal->next) {
    3501           0 :                 ea_count++;
    3502             :         }
    3503             : 
    3504           0 :         if (ea_count) {
    3505           0 :                 *pea_array = talloc_array(ctx, struct ea_struct, ea_count);
    3506           0 :                 if (*pea_array == NULL) {
    3507           0 :                         status = NT_STATUS_NO_MEMORY;
    3508           0 :                         goto fail;
    3509             :                 }
    3510           0 :                 ea_count = 0;
    3511           0 :                 for (eal = ea_list; eal; eal = eal->next) {
    3512           0 :                         (*pea_array)[ea_count++] = eal->ea;
    3513             :                 }
    3514           0 :                 *pnum_eas = ea_count;
    3515             :         }
    3516             : 
    3517           0 :   fail:
    3518             : 
    3519           0 :         if (fnum != 0xffff) {
    3520           0 :                 cli_smb2_close_fnum(cli, fnum);
    3521             :         }
    3522             : 
    3523           0 :         cli->raw_status = status;
    3524             : 
    3525           0 :         TALLOC_FREE(frame);
    3526           0 :         return status;
    3527             : }
    3528             : 
    3529             : /***************************************************************
    3530             :  Wrapper that allows SMB2 to get user quota.
    3531             :  Synchronous only.
    3532             : ***************************************************************/
    3533             : 
    3534          15 : NTSTATUS cli_smb2_get_user_quota(struct cli_state *cli,
    3535             :                                  int quota_fnum,
    3536             :                                  SMB_NTQUOTA_STRUCT *pqt)
    3537             : {
    3538           0 :         NTSTATUS status;
    3539          15 :         DATA_BLOB inbuf = data_blob_null;
    3540          15 :         DATA_BLOB info_blob = data_blob_null;
    3541          15 :         DATA_BLOB outbuf = data_blob_null;
    3542          15 :         TALLOC_CTX *frame = talloc_stackframe();
    3543           0 :         unsigned sid_len;
    3544           0 :         unsigned int offset;
    3545          15 :         struct smb2_query_quota_info query = {0};
    3546          15 :         struct file_get_quota_info info = {0};
    3547           0 :         enum ndr_err_code err;
    3548          15 :         struct ndr_push *ndr_push = NULL;
    3549             : 
    3550          15 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3551             :                 /*
    3552             :                  * Can't use sync call while an async call is in flight
    3553             :                  */
    3554           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3555           0 :                 goto fail;
    3556             :         }
    3557             : 
    3558          15 :         sid_len = ndr_size_dom_sid(&pqt->sid, 0);
    3559             : 
    3560          15 :         query.return_single = 1;
    3561             : 
    3562          15 :         info.next_entry_offset = 0;
    3563          15 :         info.sid_length = sid_len;
    3564          15 :         info.sid = pqt->sid;
    3565             : 
    3566          15 :         err = ndr_push_struct_blob(
    3567             :                         &info_blob,
    3568             :                         frame,
    3569             :                         &info,
    3570             :                         (ndr_push_flags_fn_t)ndr_push_file_get_quota_info);
    3571             : 
    3572          15 :         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
    3573           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    3574           0 :                 goto fail;
    3575             :         }
    3576             : 
    3577          15 :         query.sid_list_length = info_blob.length;
    3578          15 :         ndr_push = ndr_push_init_ctx(frame);
    3579          15 :         if (!ndr_push) {
    3580           0 :                 status = NT_STATUS_NO_MEMORY;
    3581           0 :                 goto fail;
    3582             :         }
    3583             : 
    3584          15 :         err = ndr_push_smb2_query_quota_info(ndr_push,
    3585             :                                              NDR_SCALARS | NDR_BUFFERS,
    3586             :                                              &query);
    3587             : 
    3588          15 :         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
    3589           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    3590           0 :                 goto fail;
    3591             :         }
    3592             : 
    3593          15 :         err = ndr_push_array_uint8(ndr_push, NDR_SCALARS, info_blob.data,
    3594          15 :                                    info_blob.length);
    3595             : 
    3596          15 :         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
    3597           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    3598           0 :                 goto fail;
    3599             :         }
    3600          15 :         inbuf.data = ndr_push->data;
    3601          15 :         inbuf.length = ndr_push->offset;
    3602             : 
    3603          15 :         status = cli_smb2_query_info_fnum(
    3604             :                 cli,
    3605             :                 quota_fnum,
    3606             :                 4, /* in_info_type */
    3607             :                 0,                     /* in_file_info_class */
    3608             :                 0xFFFF, /* in_max_output_length */
    3609             :                 &inbuf, /* in_input_buffer */
    3610             :                 0,      /* in_additional_info */
    3611             :                 0,      /* in_flags */
    3612             :                 frame,
    3613             :                 &outbuf);
    3614             : 
    3615          15 :         if (!NT_STATUS_IS_OK(status)) {
    3616           5 :                 goto fail;
    3617             :         }
    3618             : 
    3619          10 :         if (!parse_user_quota_record(outbuf.data, outbuf.length, &offset,
    3620             :                                      pqt)) {
    3621           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
    3622           0 :                 DEBUG(0, ("Got invalid FILE_QUOTA_INFORMATION in reply.\n"));
    3623             :         }
    3624             : 
    3625          10 : fail:
    3626          15 :         cli->raw_status = status;
    3627             : 
    3628          15 :         TALLOC_FREE(frame);
    3629          15 :         return status;
    3630             : }
    3631             : 
    3632             : /***************************************************************
    3633             :  Wrapper that allows SMB2 to list user quota.
    3634             :  Synchronous only.
    3635             : ***************************************************************/
    3636             : 
    3637           8 : NTSTATUS cli_smb2_list_user_quota_step(struct cli_state *cli,
    3638             :                                        TALLOC_CTX *mem_ctx,
    3639             :                                        int quota_fnum,
    3640             :                                        SMB_NTQUOTA_LIST **pqt_list,
    3641             :                                        bool first)
    3642             : {
    3643           0 :         NTSTATUS status;
    3644           8 :         DATA_BLOB inbuf = data_blob_null;
    3645           8 :         DATA_BLOB outbuf = data_blob_null;
    3646           8 :         TALLOC_CTX *frame = talloc_stackframe();
    3647           8 :         struct smb2_query_quota_info info = {0};
    3648           0 :         enum ndr_err_code err;
    3649             : 
    3650           8 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3651             :                 /*
    3652             :                  * Can't use sync call while an async call is in flight
    3653             :                  */
    3654           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3655           0 :                 goto cleanup;
    3656             :         }
    3657             : 
    3658           8 :         info.restart_scan = first ? 1 : 0;
    3659             : 
    3660           8 :         err = ndr_push_struct_blob(
    3661             :                         &inbuf,
    3662             :                         frame,
    3663             :                         &info,
    3664             :                         (ndr_push_flags_fn_t)ndr_push_smb2_query_quota_info);
    3665             : 
    3666           8 :         if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
    3667           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    3668           0 :                 goto cleanup;
    3669             :         }
    3670             : 
    3671           8 :         status = cli_smb2_query_info_fnum(
    3672             :                 cli,
    3673             :                 quota_fnum,
    3674             :                 4, /* in_info_type */
    3675             :                 0, /* in_file_info_class */
    3676             :                 0xFFFF, /* in_max_output_length */
    3677             :                 &inbuf, /* in_input_buffer */
    3678             :                 0,      /* in_additional_info */
    3679             :                 0,      /* in_flags */
    3680             :                 frame,
    3681             :                 &outbuf);
    3682             : 
    3683             :         /*
    3684             :          * safeguard against panic from calling parse_user_quota_list with
    3685             :          * NULL buffer
    3686             :          */
    3687           8 :         if (NT_STATUS_IS_OK(status) && outbuf.length == 0) {
    3688           0 :                 status = NT_STATUS_NO_MORE_ENTRIES;
    3689             :         }
    3690             : 
    3691           8 :         if (!NT_STATUS_IS_OK(status)) {
    3692           4 :                 goto cleanup;
    3693             :         }
    3694             : 
    3695           4 :         status = parse_user_quota_list(outbuf.data, outbuf.length, mem_ctx,
    3696             :                                        pqt_list);
    3697             : 
    3698           8 : cleanup:
    3699           8 :         cli->raw_status = status;
    3700             : 
    3701           8 :         TALLOC_FREE(frame);
    3702           8 :         return status;
    3703             : }
    3704             : 
    3705             : /***************************************************************
    3706             :  Wrapper that allows SMB2 to get file system quota.
    3707             :  Synchronous only.
    3708             : ***************************************************************/
    3709             : 
    3710           0 : NTSTATUS cli_smb2_get_fs_quota_info(struct cli_state *cli,
    3711             :                                     int quota_fnum,
    3712             :                                     SMB_NTQUOTA_STRUCT *pqt)
    3713             : {
    3714           0 :         NTSTATUS status;
    3715           0 :         DATA_BLOB outbuf = data_blob_null;
    3716           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3717             : 
    3718           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3719             :                 /*
    3720             :                  * Can't use sync call while an async call is in flight
    3721             :                  */
    3722           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3723           0 :                 goto cleanup;
    3724             :         }
    3725             : 
    3726           0 :         status = cli_smb2_query_info_fnum(
    3727             :                 cli,
    3728             :                 quota_fnum,
    3729             :                 SMB2_0_INFO_FILESYSTEM,    /* in_info_type */
    3730             :                 FSCC_FS_QUOTA_INFORMATION, /* in_file_info_class */
    3731             :                 0xFFFF,                    /* in_max_output_length */
    3732             :                 NULL,                      /* in_input_buffer */
    3733             :                 0,                         /* in_additional_info */
    3734             :                 0,                         /* in_flags */
    3735             :                 frame,
    3736             :                 &outbuf);
    3737             : 
    3738           0 :         if (!NT_STATUS_IS_OK(status)) {
    3739           0 :                 goto cleanup;
    3740             :         }
    3741             : 
    3742           0 :         status = parse_fs_quota_buffer(outbuf.data, outbuf.length, pqt);
    3743             : 
    3744           0 : cleanup:
    3745           0 :         cli->raw_status = status;
    3746             : 
    3747           0 :         TALLOC_FREE(frame);
    3748           0 :         return status;
    3749             : }
    3750             : 
    3751             : /***************************************************************
    3752             :  Wrapper that allows SMB2 to set user quota.
    3753             :  Synchronous only.
    3754             : ***************************************************************/
    3755             : 
    3756           4 : NTSTATUS cli_smb2_set_user_quota(struct cli_state *cli,
    3757             :                                  int quota_fnum,
    3758             :                                  SMB_NTQUOTA_LIST *qtl)
    3759             : {
    3760           0 :         NTSTATUS status;
    3761           4 :         DATA_BLOB inbuf = data_blob_null;
    3762           4 :         TALLOC_CTX *frame = talloc_stackframe();
    3763             : 
    3764           4 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3765             :                 /*
    3766             :                  * Can't use sync call while an async call is in flight
    3767             :                  */
    3768           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3769           0 :                 goto cleanup;
    3770             :         }
    3771             : 
    3772           4 :         status = build_user_quota_buffer(qtl, 0, talloc_tos(), &inbuf, NULL);
    3773           4 :         if (!NT_STATUS_IS_OK(status)) {
    3774           0 :                 goto cleanup;
    3775             :         }
    3776             : 
    3777           4 :         status = cli_smb2_set_info_fnum(
    3778             :                 cli,
    3779             :                 quota_fnum,
    3780             :                 4,                        /* in_info_type */
    3781             :                 0,                        /* in_file_info_class */
    3782             :                 &inbuf,                       /* in_input_buffer */
    3783             :                 0);                       /* in_additional_info */
    3784           4 : cleanup:
    3785             : 
    3786           4 :         cli->raw_status = status;
    3787             : 
    3788           4 :         TALLOC_FREE(frame);
    3789             : 
    3790           4 :         return status;
    3791             : }
    3792             : 
    3793           0 : NTSTATUS cli_smb2_set_fs_quota_info(struct cli_state *cli,
    3794             :                                     int quota_fnum,
    3795             :                                     SMB_NTQUOTA_STRUCT *pqt)
    3796             : {
    3797           0 :         NTSTATUS status;
    3798           0 :         DATA_BLOB inbuf = data_blob_null;
    3799           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3800             : 
    3801           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    3802             :                 /*
    3803             :                  * Can't use sync call while an async call is in flight
    3804             :                  */
    3805           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    3806           0 :                 goto cleanup;
    3807             :         }
    3808             : 
    3809           0 :         status = build_fs_quota_buffer(talloc_tos(), pqt, &inbuf, 0);
    3810           0 :         if (!NT_STATUS_IS_OK(status)) {
    3811           0 :                 goto cleanup;
    3812             :         }
    3813             : 
    3814           0 :         status = cli_smb2_set_info_fnum(
    3815             :                 cli,
    3816             :                 quota_fnum,
    3817             :                 SMB2_0_INFO_FILESYSTEM,    /* in_info_type */
    3818             :                 FSCC_FS_QUOTA_INFORMATION, /* in_file_info_class */
    3819             :                 &inbuf,                        /* in_input_buffer */
    3820             :                 0);                        /* in_additional_info */
    3821           0 : cleanup:
    3822           0 :         cli->raw_status = status;
    3823             : 
    3824           0 :         TALLOC_FREE(frame);
    3825           0 :         return status;
    3826             : }
    3827             : 
    3828             : struct cli_smb2_read_state {
    3829             :         struct tevent_context *ev;
    3830             :         struct cli_state *cli;
    3831             :         struct smb2_hnd *ph;
    3832             :         uint64_t start_offset;
    3833             :         uint32_t size;
    3834             :         uint32_t received;
    3835             :         uint8_t *buf;
    3836             : };
    3837             : 
    3838             : static void cli_smb2_read_done(struct tevent_req *subreq);
    3839             : 
    3840        3633 : struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx,
    3841             :                                 struct tevent_context *ev,
    3842             :                                 struct cli_state *cli,
    3843             :                                 uint16_t fnum,
    3844             :                                 off_t offset,
    3845             :                                 size_t size)
    3846             : {
    3847           0 :         NTSTATUS status;
    3848           0 :         struct tevent_req *req, *subreq;
    3849           0 :         struct cli_smb2_read_state *state;
    3850             : 
    3851        3633 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state);
    3852        3633 :         if (req == NULL) {
    3853           0 :                 return NULL;
    3854             :         }
    3855        3633 :         state->ev = ev;
    3856        3633 :         state->cli = cli;
    3857        3633 :         state->start_offset = (uint64_t)offset;
    3858        3633 :         state->size = (uint32_t)size;
    3859        3633 :         state->received = 0;
    3860        3633 :         state->buf = NULL;
    3861             : 
    3862        3633 :         status = map_fnum_to_smb2_handle(cli,
    3863             :                                         fnum,
    3864        3633 :                                         &state->ph);
    3865        3633 :         if (tevent_req_nterror(req, status)) {
    3866           0 :                 return tevent_req_post(req, ev);
    3867             :         }
    3868             : 
    3869        3633 :         subreq = smb2cli_read_send(state,
    3870        3633 :                                 state->ev,
    3871        3633 :                                 state->cli->conn,
    3872        3633 :                                 state->cli->timeout,
    3873        3633 :                                 state->cli->smb2.session,
    3874        3633 :                                 state->cli->smb2.tcon,
    3875        3633 :                                 state->size,
    3876        3633 :                                 state->start_offset,
    3877        3633 :                                 state->ph->fid_persistent,
    3878        3633 :                                 state->ph->fid_volatile,
    3879             :                                 0, /* minimum_count */
    3880             :                                 0); /* remaining_bytes */
    3881             : 
    3882        3633 :         if (tevent_req_nomem(subreq, req)) {
    3883           0 :                 return tevent_req_post(req, ev);
    3884             :         }
    3885        3633 :         tevent_req_set_callback(subreq, cli_smb2_read_done, req);
    3886        3633 :         return req;
    3887             : }
    3888             : 
    3889        3633 : static void cli_smb2_read_done(struct tevent_req *subreq)
    3890             : {
    3891        3633 :         struct tevent_req *req = tevent_req_callback_data(
    3892             :                 subreq, struct tevent_req);
    3893        3633 :         struct cli_smb2_read_state *state = tevent_req_data(
    3894             :                 req, struct cli_smb2_read_state);
    3895           0 :         NTSTATUS status;
    3896             : 
    3897        3633 :         status = smb2cli_read_recv(subreq, state,
    3898             :                                    &state->buf, &state->received);
    3899        3633 :         if (tevent_req_nterror(req, status)) {
    3900         329 :                 return;
    3901             :         }
    3902             : 
    3903        3304 :         if (state->received > state->size) {
    3904           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
    3905           0 :                 return;
    3906             :         }
    3907             : 
    3908        3304 :         tevent_req_done(req);
    3909             : }
    3910             : 
    3911        3633 : NTSTATUS cli_smb2_read_recv(struct tevent_req *req,
    3912             :                                 ssize_t *received,
    3913             :                                 uint8_t **rcvbuf)
    3914             : {
    3915           0 :         NTSTATUS status;
    3916        3633 :         struct cli_smb2_read_state *state = tevent_req_data(
    3917             :                                 req, struct cli_smb2_read_state);
    3918             : 
    3919        3633 :         if (tevent_req_is_nterror(req, &status)) {
    3920         329 :                 state->cli->raw_status = status;
    3921         329 :                 return status;
    3922             :         }
    3923             :         /*
    3924             :          * As in cli_read_andx_recv() rcvbuf is talloced from the request, so
    3925             :          * better make sure that you copy it away before you talloc_free(req).
    3926             :          * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it!
    3927             :          */
    3928        3304 :         *received = (ssize_t)state->received;
    3929        3304 :         *rcvbuf = state->buf;
    3930        3304 :         state->cli->raw_status = NT_STATUS_OK;
    3931        3304 :         return NT_STATUS_OK;
    3932             : }
    3933             : 
    3934             : struct cli_smb2_write_state {
    3935             :         struct tevent_context *ev;
    3936             :         struct cli_state *cli;
    3937             :         struct smb2_hnd *ph;
    3938             :         uint32_t flags;
    3939             :         const uint8_t *buf;
    3940             :         uint64_t offset;
    3941             :         uint32_t size;
    3942             :         uint32_t written;
    3943             : };
    3944             : 
    3945             : static void cli_smb2_write_written(struct tevent_req *req);
    3946             : 
    3947        2291 : struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx,
    3948             :                                         struct tevent_context *ev,
    3949             :                                         struct cli_state *cli,
    3950             :                                         uint16_t fnum,
    3951             :                                         uint16_t mode,
    3952             :                                         const uint8_t *buf,
    3953             :                                         off_t offset,
    3954             :                                         size_t size)
    3955             : {
    3956           0 :         NTSTATUS status;
    3957        2291 :         struct tevent_req *req, *subreq = NULL;
    3958        2291 :         struct cli_smb2_write_state *state = NULL;
    3959             : 
    3960        2291 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state);
    3961        2291 :         if (req == NULL) {
    3962           0 :                 return NULL;
    3963             :         }
    3964        2291 :         state->ev = ev;
    3965        2291 :         state->cli = cli;
    3966             :         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
    3967        2291 :         state->flags = (uint32_t)mode;
    3968        2291 :         state->buf = buf;
    3969        2291 :         state->offset = (uint64_t)offset;
    3970        2291 :         state->size = (uint32_t)size;
    3971        2291 :         state->written = 0;
    3972             : 
    3973        2291 :         status = map_fnum_to_smb2_handle(cli,
    3974             :                                         fnum,
    3975        2291 :                                         &state->ph);
    3976        2291 :         if (tevent_req_nterror(req, status)) {
    3977           0 :                 return tevent_req_post(req, ev);
    3978             :         }
    3979             : 
    3980        2291 :         subreq = smb2cli_write_send(state,
    3981        2291 :                                 state->ev,
    3982        2291 :                                 state->cli->conn,
    3983        2291 :                                 state->cli->timeout,
    3984        2291 :                                 state->cli->smb2.session,
    3985        2291 :                                 state->cli->smb2.tcon,
    3986        2291 :                                 state->size,
    3987        2291 :                                 state->offset,
    3988        2291 :                                 state->ph->fid_persistent,
    3989        2291 :                                 state->ph->fid_volatile,
    3990             :                                 0, /* remaining_bytes */
    3991        2291 :                                 state->flags, /* flags */
    3992        2291 :                                 state->buf);
    3993             : 
    3994        2291 :         if (tevent_req_nomem(subreq, req)) {
    3995           0 :                 return tevent_req_post(req, ev);
    3996             :         }
    3997        2291 :         tevent_req_set_callback(subreq, cli_smb2_write_written, req);
    3998        2291 :         return req;
    3999             : }
    4000             : 
    4001        2291 : static void cli_smb2_write_written(struct tevent_req *subreq)
    4002             : {
    4003        2291 :         struct tevent_req *req = tevent_req_callback_data(
    4004             :                 subreq, struct tevent_req);
    4005        2291 :         struct cli_smb2_write_state *state = tevent_req_data(
    4006             :                 req, struct cli_smb2_write_state);
    4007           0 :         NTSTATUS status;
    4008           0 :         uint32_t written;
    4009             : 
    4010        2291 :         status = smb2cli_write_recv(subreq, &written);
    4011        2291 :         TALLOC_FREE(subreq);
    4012        2291 :         if (tevent_req_nterror(req, status)) {
    4013           0 :                 return;
    4014             :         }
    4015             : 
    4016        2291 :         state->written = written;
    4017             : 
    4018        2291 :         tevent_req_done(req);
    4019             : }
    4020             : 
    4021        2291 : NTSTATUS cli_smb2_write_recv(struct tevent_req *req,
    4022             :                              size_t *pwritten)
    4023             : {
    4024        2291 :         struct cli_smb2_write_state *state = tevent_req_data(
    4025             :                 req, struct cli_smb2_write_state);
    4026           0 :         NTSTATUS status;
    4027             : 
    4028        2291 :         if (tevent_req_is_nterror(req, &status)) {
    4029           0 :                 state->cli->raw_status = status;
    4030           0 :                 tevent_req_received(req);
    4031           0 :                 return status;
    4032             :         }
    4033             : 
    4034        2291 :         if (pwritten != NULL) {
    4035        2291 :                 *pwritten = (size_t)state->written;
    4036             :         }
    4037        2291 :         state->cli->raw_status = NT_STATUS_OK;
    4038        2291 :         tevent_req_received(req);
    4039        2291 :         return NT_STATUS_OK;
    4040             : }
    4041             : 
    4042             : /***************************************************************
    4043             :  Wrapper that allows SMB2 async write using an fnum.
    4044             :  This is mostly cut-and-paste from Volker's code inside
    4045             :  source3/libsmb/clireadwrite.c, adapted for SMB2.
    4046             : 
    4047             :  Done this way so I can reuse all the logic inside cli_push()
    4048             :  for free :-).
    4049             : ***************************************************************/
    4050             : 
    4051             : struct cli_smb2_writeall_state {
    4052             :         struct tevent_context *ev;
    4053             :         struct cli_state *cli;
    4054             :         struct smb2_hnd *ph;
    4055             :         uint32_t flags;
    4056             :         const uint8_t *buf;
    4057             :         uint64_t offset;
    4058             :         uint32_t size;
    4059             :         uint32_t written;
    4060             : };
    4061             : 
    4062             : static void cli_smb2_writeall_written(struct tevent_req *req);
    4063             : 
    4064         495 : struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx,
    4065             :                                         struct tevent_context *ev,
    4066             :                                         struct cli_state *cli,
    4067             :                                         uint16_t fnum,
    4068             :                                         uint16_t mode,
    4069             :                                         const uint8_t *buf,
    4070             :                                         off_t offset,
    4071             :                                         size_t size)
    4072             : {
    4073           0 :         NTSTATUS status;
    4074         495 :         struct tevent_req *req, *subreq = NULL;
    4075         495 :         struct cli_smb2_writeall_state *state = NULL;
    4076           0 :         uint32_t to_write;
    4077           0 :         uint32_t max_size;
    4078           0 :         bool ok;
    4079             : 
    4080         495 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state);
    4081         495 :         if (req == NULL) {
    4082           0 :                 return NULL;
    4083             :         }
    4084         495 :         state->ev = ev;
    4085         495 :         state->cli = cli;
    4086             :         /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */
    4087         495 :         state->flags = (uint32_t)mode;
    4088         495 :         state->buf = buf;
    4089         495 :         state->offset = (uint64_t)offset;
    4090         495 :         state->size = (uint32_t)size;
    4091         495 :         state->written = 0;
    4092             : 
    4093         495 :         status = map_fnum_to_smb2_handle(cli,
    4094             :                                         fnum,
    4095         495 :                                         &state->ph);
    4096         495 :         if (tevent_req_nterror(req, status)) {
    4097           0 :                 return tevent_req_post(req, ev);
    4098             :         }
    4099             : 
    4100         495 :         to_write = state->size;
    4101         495 :         max_size = smb2cli_conn_max_write_size(state->cli->conn);
    4102         495 :         to_write = MIN(max_size, to_write);
    4103         495 :         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
    4104         495 :         if (ok) {
    4105         495 :                 to_write = MIN(max_size, to_write);
    4106             :         }
    4107             : 
    4108         495 :         subreq = smb2cli_write_send(state,
    4109         495 :                                 state->ev,
    4110         495 :                                 state->cli->conn,
    4111         495 :                                 state->cli->timeout,
    4112         495 :                                 state->cli->smb2.session,
    4113         495 :                                 state->cli->smb2.tcon,
    4114             :                                 to_write,
    4115         495 :                                 state->offset,
    4116         495 :                                 state->ph->fid_persistent,
    4117         495 :                                 state->ph->fid_volatile,
    4118             :                                 0, /* remaining_bytes */
    4119         495 :                                 state->flags, /* flags */
    4120         495 :                                 state->buf + state->written);
    4121             : 
    4122         495 :         if (tevent_req_nomem(subreq, req)) {
    4123           0 :                 return tevent_req_post(req, ev);
    4124             :         }
    4125         495 :         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
    4126         495 :         return req;
    4127             : }
    4128             : 
    4129         570 : static void cli_smb2_writeall_written(struct tevent_req *subreq)
    4130             : {
    4131         570 :         struct tevent_req *req = tevent_req_callback_data(
    4132             :                 subreq, struct tevent_req);
    4133         570 :         struct cli_smb2_writeall_state *state = tevent_req_data(
    4134             :                 req, struct cli_smb2_writeall_state);
    4135           0 :         NTSTATUS status;
    4136           0 :         uint32_t written, to_write;
    4137           0 :         uint32_t max_size;
    4138           0 :         bool ok;
    4139             : 
    4140         570 :         status = smb2cli_write_recv(subreq, &written);
    4141         570 :         TALLOC_FREE(subreq);
    4142         570 :         if (tevent_req_nterror(req, status)) {
    4143         495 :                 return;
    4144             :         }
    4145             : 
    4146         570 :         state->written += written;
    4147             : 
    4148         570 :         if (state->written > state->size) {
    4149           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
    4150           0 :                 return;
    4151             :         }
    4152             : 
    4153         570 :         to_write = state->size - state->written;
    4154             : 
    4155         570 :         if (to_write == 0) {
    4156         495 :                 tevent_req_done(req);
    4157         495 :                 return;
    4158             :         }
    4159             : 
    4160          75 :         max_size = smb2cli_conn_max_write_size(state->cli->conn);
    4161          75 :         to_write = MIN(max_size, to_write);
    4162          75 :         ok = smb2cli_conn_req_possible(state->cli->conn, &max_size);
    4163          75 :         if (ok) {
    4164          75 :                 to_write = MIN(max_size, to_write);
    4165             :         }
    4166             : 
    4167          75 :         subreq = smb2cli_write_send(state,
    4168             :                                 state->ev,
    4169          75 :                                 state->cli->conn,
    4170          75 :                                 state->cli->timeout,
    4171          75 :                                 state->cli->smb2.session,
    4172          75 :                                 state->cli->smb2.tcon,
    4173             :                                 to_write,
    4174          75 :                                 state->offset + state->written,
    4175          75 :                                 state->ph->fid_persistent,
    4176          75 :                                 state->ph->fid_volatile,
    4177             :                                 0, /* remaining_bytes */
    4178             :                                 state->flags, /* flags */
    4179          75 :                                 state->buf + state->written);
    4180             : 
    4181          75 :         if (tevent_req_nomem(subreq, req)) {
    4182           0 :                 return;
    4183             :         }
    4184          75 :         tevent_req_set_callback(subreq, cli_smb2_writeall_written, req);
    4185             : }
    4186             : 
    4187         495 : NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req,
    4188             :                                 size_t *pwritten)
    4189             : {
    4190         495 :         struct cli_smb2_writeall_state *state = tevent_req_data(
    4191             :                 req, struct cli_smb2_writeall_state);
    4192           0 :         NTSTATUS status;
    4193             : 
    4194         495 :         if (tevent_req_is_nterror(req, &status)) {
    4195           0 :                 state->cli->raw_status = status;
    4196           0 :                 return status;
    4197             :         }
    4198         495 :         if (pwritten != NULL) {
    4199         495 :                 *pwritten = (size_t)state->written;
    4200             :         }
    4201         495 :         state->cli->raw_status = NT_STATUS_OK;
    4202         495 :         return NT_STATUS_OK;
    4203             : }
    4204             : 
    4205             : struct cli_smb2_splice_state {
    4206             :         struct tevent_context *ev;
    4207             :         struct cli_state *cli;
    4208             :         struct smb2_hnd *src_ph;
    4209             :         struct smb2_hnd *dst_ph;
    4210             :         int (*splice_cb)(off_t n, void *priv);
    4211             :         void *priv;
    4212             :         off_t written;
    4213             :         off_t size;
    4214             :         off_t src_offset;
    4215             :         off_t dst_offset;
    4216             :         bool resized;
    4217             :         struct req_resume_key_rsp resume_rsp;
    4218             :         struct srv_copychunk_copy cc_copy;
    4219             : };
    4220             : 
    4221             : static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
    4222             :                                       struct tevent_req *req);
    4223             : 
    4224           0 : static void cli_splice_copychunk_done(struct tevent_req *subreq)
    4225             : {
    4226           0 :         struct tevent_req *req = tevent_req_callback_data(
    4227             :                 subreq, struct tevent_req);
    4228           0 :         struct cli_smb2_splice_state *state =
    4229           0 :                 tevent_req_data(req,
    4230             :                 struct cli_smb2_splice_state);
    4231           0 :         struct smbXcli_conn *conn = state->cli->conn;
    4232           0 :         DATA_BLOB out_input_buffer = data_blob_null;
    4233           0 :         DATA_BLOB out_output_buffer = data_blob_null;
    4234           0 :         struct srv_copychunk_rsp cc_copy_rsp;
    4235           0 :         enum ndr_err_code ndr_ret;
    4236           0 :         NTSTATUS status;
    4237             : 
    4238           0 :         status = smb2cli_ioctl_recv(subreq, state,
    4239             :                                     &out_input_buffer,
    4240             :                                     &out_output_buffer);
    4241           0 :         TALLOC_FREE(subreq);
    4242           0 :         if ((!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER) ||
    4243           0 :              state->resized) && tevent_req_nterror(req, status)) {
    4244           0 :                 return;
    4245             :         }
    4246             : 
    4247           0 :         ndr_ret = ndr_pull_struct_blob(&out_output_buffer, state, &cc_copy_rsp,
    4248             :                         (ndr_pull_flags_fn_t)ndr_pull_srv_copychunk_rsp);
    4249           0 :         if (ndr_ret != NDR_ERR_SUCCESS) {
    4250           0 :                 DEBUG(0, ("failed to unmarshall copy chunk rsp\n"));
    4251           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
    4252           0 :                 return;
    4253             :         }
    4254             : 
    4255           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
    4256           0 :                 uint32_t max_chunks = MIN(cc_copy_rsp.chunks_written,
    4257             :                              cc_copy_rsp.total_bytes_written / cc_copy_rsp.chunk_bytes_written);
    4258           0 :                 if ((cc_copy_rsp.chunk_bytes_written > smb2cli_conn_cc_chunk_len(conn) ||
    4259           0 :                      max_chunks > smb2cli_conn_cc_max_chunks(conn)) &&
    4260           0 :                      tevent_req_nterror(req, status)) {
    4261           0 :                         return;
    4262             :                 }
    4263             : 
    4264           0 :                 state->resized = true;
    4265           0 :                 smb2cli_conn_set_cc_chunk_len(conn, cc_copy_rsp.chunk_bytes_written);
    4266           0 :                 smb2cli_conn_set_cc_max_chunks(conn, max_chunks);
    4267             :         } else {
    4268           0 :                 if ((state->src_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
    4269           0 :                     (state->dst_offset > INT64_MAX - cc_copy_rsp.total_bytes_written) ||
    4270           0 :                     (state->written > INT64_MAX - cc_copy_rsp.total_bytes_written)) {
    4271           0 :                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
    4272           0 :                         return;
    4273             :                 }
    4274           0 :                 state->src_offset += cc_copy_rsp.total_bytes_written;
    4275           0 :                 state->dst_offset += cc_copy_rsp.total_bytes_written;
    4276           0 :                 state->written += cc_copy_rsp.total_bytes_written;
    4277           0 :                 if (!state->splice_cb(state->written, state->priv)) {
    4278           0 :                         tevent_req_nterror(req, NT_STATUS_CANCELLED);
    4279           0 :                         return;
    4280             :                 }
    4281             :         }
    4282             : 
    4283           0 :         cli_splice_copychunk_send(state, req);
    4284             : }
    4285             : 
    4286           0 : static void cli_splice_copychunk_send(struct cli_smb2_splice_state *state,
    4287             :                                       struct tevent_req *req)
    4288             : {
    4289           0 :         struct tevent_req *subreq;
    4290           0 :         enum ndr_err_code ndr_ret;
    4291           0 :         struct smbXcli_conn *conn = state->cli->conn;
    4292           0 :         struct srv_copychunk_copy *cc_copy = &state->cc_copy;
    4293           0 :         off_t src_offset = state->src_offset;
    4294           0 :         off_t dst_offset = state->dst_offset;
    4295           0 :         uint32_t req_len = MIN(smb2cli_conn_cc_chunk_len(conn) * smb2cli_conn_cc_max_chunks(conn),
    4296             :                                state->size - state->written);
    4297           0 :         DATA_BLOB in_input_buffer = data_blob_null;
    4298           0 :         DATA_BLOB in_output_buffer = data_blob_null;
    4299             : 
    4300           0 :         if (state->size - state->written == 0) {
    4301           0 :                 tevent_req_done(req);
    4302           0 :                 return;
    4303             :         }
    4304             : 
    4305           0 :         cc_copy->chunk_count = 0;
    4306           0 :         while (req_len) {
    4307           0 :                 cc_copy->chunks[cc_copy->chunk_count].source_off = src_offset;
    4308           0 :                 cc_copy->chunks[cc_copy->chunk_count].target_off = dst_offset;
    4309           0 :                 cc_copy->chunks[cc_copy->chunk_count].length = MIN(req_len,
    4310             :                                                                    smb2cli_conn_cc_chunk_len(conn));
    4311           0 :                 if (req_len < cc_copy->chunks[cc_copy->chunk_count].length) {
    4312           0 :                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
    4313           0 :                         return;
    4314             :                 }
    4315           0 :                 req_len -= cc_copy->chunks[cc_copy->chunk_count].length;
    4316           0 :                 if ((src_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length) ||
    4317           0 :                     (dst_offset > INT64_MAX - cc_copy->chunks[cc_copy->chunk_count].length)) {
    4318           0 :                         tevent_req_nterror(req, NT_STATUS_FILE_TOO_LARGE);
    4319           0 :                         return;
    4320             :                 }
    4321           0 :                 src_offset += cc_copy->chunks[cc_copy->chunk_count].length;
    4322           0 :                 dst_offset += cc_copy->chunks[cc_copy->chunk_count].length;
    4323           0 :                 cc_copy->chunk_count++;
    4324             :         }
    4325             : 
    4326           0 :         ndr_ret = ndr_push_struct_blob(&in_input_buffer, state, cc_copy,
    4327             :                                        (ndr_push_flags_fn_t)ndr_push_srv_copychunk_copy);
    4328           0 :         if (ndr_ret != NDR_ERR_SUCCESS) {
    4329           0 :                 DEBUG(0, ("failed to marshall copy chunk req\n"));
    4330           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
    4331           0 :                 return;
    4332             :         }
    4333             : 
    4334           0 :         subreq = smb2cli_ioctl_send(state, state->ev, state->cli->conn,
    4335           0 :                                state->cli->timeout,
    4336           0 :                                state->cli->smb2.session,
    4337           0 :                                state->cli->smb2.tcon,
    4338           0 :                                state->dst_ph->fid_persistent, /* in_fid_persistent */
    4339           0 :                                state->dst_ph->fid_volatile, /* in_fid_volatile */
    4340             :                                FSCTL_SRV_COPYCHUNK_WRITE,
    4341             :                                0, /* in_max_input_length */
    4342             :                                &in_input_buffer,
    4343             :                                12, /* in_max_output_length */
    4344             :                                &in_output_buffer,
    4345             :                                SMB2_IOCTL_FLAG_IS_FSCTL);
    4346           0 :         if (tevent_req_nomem(subreq, req)) {
    4347           0 :                 return;
    4348             :         }
    4349           0 :         tevent_req_set_callback(subreq,
    4350             :                                 cli_splice_copychunk_done,
    4351             :                                 req);
    4352             : }
    4353             : 
    4354           0 : static void cli_splice_key_done(struct tevent_req *subreq)
    4355             : {
    4356           0 :         struct tevent_req *req = tevent_req_callback_data(
    4357             :                 subreq, struct tevent_req);
    4358           0 :         struct cli_smb2_splice_state *state =
    4359           0 :                 tevent_req_data(req,
    4360             :                 struct cli_smb2_splice_state);
    4361           0 :         enum ndr_err_code ndr_ret;
    4362           0 :         NTSTATUS status;
    4363             : 
    4364           0 :         DATA_BLOB out_input_buffer = data_blob_null;
    4365           0 :         DATA_BLOB out_output_buffer = data_blob_null;
    4366             : 
    4367           0 :         status = smb2cli_ioctl_recv(subreq, state,
    4368             :                                     &out_input_buffer,
    4369             :                                     &out_output_buffer);
    4370           0 :         TALLOC_FREE(subreq);
    4371           0 :         if (tevent_req_nterror(req, status)) {
    4372           0 :                 return;
    4373             :         }
    4374             : 
    4375           0 :         ndr_ret = ndr_pull_struct_blob(&out_output_buffer,
    4376           0 :                         state, &state->resume_rsp,
    4377             :                         (ndr_pull_flags_fn_t)ndr_pull_req_resume_key_rsp);
    4378           0 :         if (ndr_ret != NDR_ERR_SUCCESS) {
    4379           0 :                 DEBUG(0, ("failed to unmarshall resume key rsp\n"));
    4380           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
    4381           0 :                 return;
    4382             :         }
    4383             : 
    4384           0 :         memcpy(&state->cc_copy.source_key,
    4385           0 :                &state->resume_rsp.resume_key,
    4386             :                sizeof state->resume_rsp.resume_key);
    4387             : 
    4388           0 :         cli_splice_copychunk_send(state, req);
    4389             : }
    4390             : 
    4391           0 : struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
    4392             :                                 struct tevent_context *ev,
    4393             :                                 struct cli_state *cli,
    4394             :                                 uint16_t src_fnum, uint16_t dst_fnum,
    4395             :                                 off_t size, off_t src_offset, off_t dst_offset,
    4396             :                                 int (*splice_cb)(off_t n, void *priv),
    4397             :                                 void *priv)
    4398             : {
    4399           0 :         struct tevent_req *req;
    4400           0 :         struct tevent_req *subreq;
    4401           0 :         struct cli_smb2_splice_state *state;
    4402           0 :         NTSTATUS status;
    4403           0 :         DATA_BLOB in_input_buffer = data_blob_null;
    4404           0 :         DATA_BLOB in_output_buffer = data_blob_null;
    4405             : 
    4406           0 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_splice_state);
    4407           0 :         if (req == NULL) {
    4408           0 :                 return NULL;
    4409             :         }
    4410           0 :         state->cli = cli;
    4411           0 :         state->ev = ev;
    4412           0 :         state->splice_cb = splice_cb;
    4413           0 :         state->priv = priv;
    4414           0 :         state->size = size;
    4415           0 :         state->written = 0;
    4416           0 :         state->src_offset = src_offset;
    4417           0 :         state->dst_offset = dst_offset;
    4418           0 :         state->cc_copy.chunks = talloc_array(state,
    4419             :                                              struct srv_copychunk,
    4420             :                                              smb2cli_conn_cc_max_chunks(cli->conn));
    4421           0 :         if (state->cc_copy.chunks == NULL) {
    4422           0 :                 return NULL;
    4423             :         }
    4424             : 
    4425           0 :         status = map_fnum_to_smb2_handle(cli, src_fnum, &state->src_ph);
    4426           0 :         if (tevent_req_nterror(req, status))
    4427           0 :                 return tevent_req_post(req, ev);
    4428             : 
    4429           0 :         status = map_fnum_to_smb2_handle(cli, dst_fnum, &state->dst_ph);
    4430           0 :         if (tevent_req_nterror(req, status))
    4431           0 :                 return tevent_req_post(req, ev);
    4432             : 
    4433           0 :         subreq = smb2cli_ioctl_send(state, ev, cli->conn,
    4434           0 :                                cli->timeout,
    4435             :                                cli->smb2.session,
    4436             :                                cli->smb2.tcon,
    4437           0 :                                state->src_ph->fid_persistent, /* in_fid_persistent */
    4438           0 :                                state->src_ph->fid_volatile, /* in_fid_volatile */
    4439             :                                FSCTL_SRV_REQUEST_RESUME_KEY,
    4440             :                                0, /* in_max_input_length */
    4441             :                                &in_input_buffer,
    4442             :                                32, /* in_max_output_length */
    4443             :                                &in_output_buffer,
    4444             :                                SMB2_IOCTL_FLAG_IS_FSCTL);
    4445           0 :         if (tevent_req_nomem(subreq, req)) {
    4446           0 :                 return NULL;
    4447             :         }
    4448           0 :         tevent_req_set_callback(subreq,
    4449             :                                 cli_splice_key_done,
    4450             :                                 req);
    4451             : 
    4452           0 :         return req;
    4453             : }
    4454             : 
    4455           0 : NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
    4456             : {
    4457           0 :         struct cli_smb2_splice_state *state = tevent_req_data(
    4458             :                 req, struct cli_smb2_splice_state);
    4459           0 :         NTSTATUS status;
    4460             : 
    4461           0 :         if (tevent_req_is_nterror(req, &status)) {
    4462           0 :                 state->cli->raw_status = status;
    4463           0 :                 tevent_req_received(req);
    4464           0 :                 return status;
    4465             :         }
    4466           0 :         if (written != NULL) {
    4467           0 :                 *written = state->written;
    4468             :         }
    4469           0 :         state->cli->raw_status = NT_STATUS_OK;
    4470           0 :         tevent_req_received(req);
    4471           0 :         return NT_STATUS_OK;
    4472             : }
    4473             : 
    4474             : /***************************************************************
    4475             :  SMB2 enum shadow copy data.
    4476             : ***************************************************************/
    4477             : 
    4478             : struct cli_smb2_shadow_copy_data_fnum_state {
    4479             :         struct cli_state *cli;
    4480             :         uint16_t fnum;
    4481             :         struct smb2_hnd *ph;
    4482             :         DATA_BLOB out_input_buffer;
    4483             :         DATA_BLOB out_output_buffer;
    4484             : };
    4485             : 
    4486             : static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
    4487             : 
    4488        1616 : static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
    4489             :                                         TALLOC_CTX *mem_ctx,
    4490             :                                         struct tevent_context *ev,
    4491             :                                         struct cli_state *cli,
    4492             :                                         uint16_t fnum,
    4493             :                                         bool get_names)
    4494             : {
    4495           0 :         struct tevent_req *req, *subreq;
    4496           0 :         struct cli_smb2_shadow_copy_data_fnum_state *state;
    4497           0 :         NTSTATUS status;
    4498             : 
    4499        1616 :         req = tevent_req_create(mem_ctx, &state,
    4500             :                                 struct cli_smb2_shadow_copy_data_fnum_state);
    4501        1616 :         if (req == NULL) {
    4502           0 :                 return NULL;
    4503             :         }
    4504             : 
    4505        1616 :         state->cli = cli;
    4506        1616 :         state->fnum = fnum;
    4507             : 
    4508        1616 :         status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
    4509        1616 :         if (tevent_req_nterror(req, status)) {
    4510           0 :                 return tevent_req_post(req, ev);
    4511             :         }
    4512             : 
    4513             :         /*
    4514             :          * TODO. Under SMB2 we should send a zero max_output_length
    4515             :          * ioctl to get the required size, then send another ioctl
    4516             :          * to get the data, but the current SMB1 implementation just
    4517             :          * does one roundtrip with a 64K buffer size. Do the same
    4518             :          * for now. JRA.
    4519             :          */
    4520             : 
    4521        1616 :         subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
    4522        1616 :                         state->cli->timeout,
    4523        1616 :                         state->cli->smb2.session,
    4524        1616 :                         state->cli->smb2.tcon,
    4525        1616 :                         state->ph->fid_persistent, /* in_fid_persistent */
    4526        1616 :                         state->ph->fid_volatile, /* in_fid_volatile */
    4527             :                         FSCTL_GET_SHADOW_COPY_DATA,
    4528             :                         0, /* in_max_input_length */
    4529             :                         NULL, /* in_input_buffer */
    4530             :                         get_names ?
    4531             :                                 CLI_BUFFER_SIZE : 16, /* in_max_output_length */
    4532             :                         NULL, /* in_output_buffer */
    4533             :                         SMB2_IOCTL_FLAG_IS_FSCTL);
    4534             : 
    4535        1616 :         if (tevent_req_nomem(subreq, req)) {
    4536           0 :                 return tevent_req_post(req, ev);
    4537             :         }
    4538        1616 :         tevent_req_set_callback(subreq,
    4539             :                                 cli_smb2_shadow_copy_data_fnum_done,
    4540             :                                 req);
    4541             : 
    4542        1616 :         return req;
    4543             : }
    4544             : 
    4545        1616 : static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
    4546             : {
    4547        1616 :         struct tevent_req *req = tevent_req_callback_data(
    4548             :                 subreq, struct tevent_req);
    4549        1616 :         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
    4550             :                 req, struct cli_smb2_shadow_copy_data_fnum_state);
    4551           0 :         NTSTATUS status;
    4552             : 
    4553        1616 :         status = smb2cli_ioctl_recv(subreq, state,
    4554             :                                 &state->out_input_buffer,
    4555             :                                 &state->out_output_buffer);
    4556        1616 :         tevent_req_simple_finish_ntstatus(subreq, status);
    4557        1616 : }
    4558             : 
    4559        1616 : static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
    4560             :                                 TALLOC_CTX *mem_ctx,
    4561             :                                 bool get_names,
    4562             :                                 char ***pnames,
    4563             :                                 int *pnum_names)
    4564             : {
    4565        1616 :         struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
    4566             :                 req, struct cli_smb2_shadow_copy_data_fnum_state);
    4567        1616 :         char **names = NULL;
    4568        1616 :         uint32_t num_names = 0;
    4569        1616 :         uint32_t num_names_returned = 0;
    4570        1616 :         uint32_t dlength = 0;
    4571           0 :         uint32_t i;
    4572        1616 :         uint8_t *endp = NULL;
    4573           0 :         NTSTATUS status;
    4574             : 
    4575        1616 :         if (tevent_req_is_nterror(req, &status)) {
    4576         202 :                 return status;
    4577             :         }
    4578             : 
    4579        1414 :         if (state->out_output_buffer.length < 16) {
    4580           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    4581             :         }
    4582             : 
    4583        1414 :         num_names = IVAL(state->out_output_buffer.data, 0);
    4584        1414 :         num_names_returned = IVAL(state->out_output_buffer.data, 4);
    4585        1414 :         dlength = IVAL(state->out_output_buffer.data, 8);
    4586             : 
    4587        1414 :         if (num_names > 0x7FFFFFFF) {
    4588           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    4589             :         }
    4590             : 
    4591        1414 :         if (get_names == false) {
    4592         707 :                 *pnum_names = (int)num_names;
    4593         707 :                 return NT_STATUS_OK;
    4594             :         }
    4595         707 :         if (num_names != num_names_returned) {
    4596           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    4597             :         }
    4598         707 :         if (dlength + 12 < 12) {
    4599           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    4600             :         }
    4601             :         /*
    4602             :          * NB. The below is an allowable return if there are
    4603             :          * more snapshots than the buffer size we told the
    4604             :          * server we can receive. We currently don't support
    4605             :          * this.
    4606             :          */
    4607         707 :         if (dlength + 12 > state->out_output_buffer.length) {
    4608           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    4609             :         }
    4610         707 :         if (state->out_output_buffer.length +
    4611             :                         (2 * sizeof(SHADOW_COPY_LABEL)) <
    4612             :                                 state->out_output_buffer.length) {
    4613           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    4614             :         }
    4615             : 
    4616         707 :         names = talloc_array(mem_ctx, char *, num_names_returned);
    4617         707 :         if (names == NULL) {
    4618           0 :                 return NT_STATUS_NO_MEMORY;
    4619             :         }
    4620             : 
    4621         707 :         endp = state->out_output_buffer.data +
    4622         707 :                         state->out_output_buffer.length;
    4623             : 
    4624        2812 :         for (i=0; i<num_names_returned; i++) {
    4625           0 :                 bool ret;
    4626           0 :                 uint8_t *src;
    4627           0 :                 size_t converted_size;
    4628             : 
    4629        2105 :                 src = state->out_output_buffer.data + 12 +
    4630        2105 :                         (i * 2 * sizeof(SHADOW_COPY_LABEL));
    4631             : 
    4632        2105 :                 if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
    4633           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
    4634             :                 }
    4635        2105 :                 ret = convert_string_talloc(
    4636             :                         names, CH_UTF16LE, CH_UNIX,
    4637             :                         src, 2 * sizeof(SHADOW_COPY_LABEL),
    4638        2105 :                         &names[i], &converted_size);
    4639        2105 :                 if (!ret) {
    4640           0 :                         TALLOC_FREE(names);
    4641           0 :                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
    4642             :                 }
    4643             :         }
    4644         707 :         *pnum_names = num_names;
    4645         707 :         *pnames = names;
    4646         707 :         return NT_STATUS_OK;
    4647             : }
    4648             : 
    4649        1616 : NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
    4650             :                                 struct cli_state *cli,
    4651             :                                 uint16_t fnum,
    4652             :                                 bool get_names,
    4653             :                                 char ***pnames,
    4654             :                                 int *pnum_names)
    4655             : {
    4656        1616 :         TALLOC_CTX *frame = talloc_stackframe();
    4657           0 :         struct tevent_context *ev;
    4658           0 :         struct tevent_req *req;
    4659        1616 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    4660             : 
    4661        1616 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    4662             :                 /*
    4663             :                  * Can't use sync call while an async call is in flight
    4664             :                  */
    4665           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    4666           0 :                 goto fail;
    4667             :         }
    4668        1616 :         ev = samba_tevent_context_init(frame);
    4669        1616 :         if (ev == NULL) {
    4670           0 :                 goto fail;
    4671             :         }
    4672        1616 :         req = cli_smb2_shadow_copy_data_fnum_send(frame,
    4673             :                                         ev,
    4674             :                                         cli,
    4675             :                                         fnum,
    4676             :                                         get_names);
    4677        1616 :         if (req == NULL) {
    4678           0 :                 goto fail;
    4679             :         }
    4680        1616 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    4681           0 :                 goto fail;
    4682             :         }
    4683        1616 :         status = cli_smb2_shadow_copy_data_fnum_recv(req,
    4684             :                                                 mem_ctx,
    4685             :                                                 get_names,
    4686             :                                                 pnames,
    4687             :                                                 pnum_names);
    4688        1616 :  fail:
    4689        1616 :         cli->raw_status = status;
    4690             : 
    4691        1616 :         TALLOC_FREE(frame);
    4692        1616 :         return status;
    4693             : }
    4694             : 
    4695             : /***************************************************************
    4696             :  Wrapper that allows SMB2 to truncate a file.
    4697             :  Synchronous only.
    4698             : ***************************************************************/
    4699             : 
    4700          50 : NTSTATUS cli_smb2_ftruncate(struct cli_state *cli,
    4701             :                         uint16_t fnum,
    4702             :                         uint64_t newsize)
    4703             : {
    4704           0 :         NTSTATUS status;
    4705          50 :         uint8_t buf[8] = {0};
    4706          50 :         DATA_BLOB inbuf = { .data = buf, .length = sizeof(buf) };
    4707          50 :         TALLOC_CTX *frame = talloc_stackframe();
    4708             : 
    4709          50 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    4710             :                 /*
    4711             :                  * Can't use sync call while an async call is in flight
    4712             :                  */
    4713           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    4714           0 :                 goto fail;
    4715             :         }
    4716             : 
    4717          50 :         SBVAL(buf, 0, newsize);
    4718             : 
    4719             :         /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
    4720             :            level 20 (SMB_FILE_END_OF_FILE_INFORMATION - 1000). */
    4721             : 
    4722          50 :         status = cli_smb2_set_info_fnum(
    4723             :                 cli,
    4724             :                 fnum,
    4725             :                 SMB2_0_INFO_FILE,                  /* in_info_type */
    4726             :                 FSCC_FILE_END_OF_FILE_INFORMATION, /* in_file_info_class */
    4727             :                 &inbuf,                                /* in_input_buffer */
    4728             :                 0);
    4729             : 
    4730          50 :   fail:
    4731             : 
    4732          50 :         cli->raw_status = status;
    4733             : 
    4734          50 :         TALLOC_FREE(frame);
    4735          50 :         return status;
    4736             : }
    4737             : 
    4738             : struct cli_smb2_notify_state {
    4739             :         struct tevent_req *subreq;
    4740             :         struct notify_change *changes;
    4741             :         size_t num_changes;
    4742             : };
    4743             : 
    4744             : static void cli_smb2_notify_done(struct tevent_req *subreq);
    4745             : static bool cli_smb2_notify_cancel(struct tevent_req *req);
    4746             : 
    4747          42 : struct tevent_req *cli_smb2_notify_send(
    4748             :         TALLOC_CTX *mem_ctx,
    4749             :         struct tevent_context *ev,
    4750             :         struct cli_state *cli,
    4751             :         uint16_t fnum,
    4752             :         uint32_t buffer_size,
    4753             :         uint32_t completion_filter,
    4754             :         bool recursive)
    4755             : {
    4756          42 :         struct tevent_req *req = NULL;
    4757          42 :         struct cli_smb2_notify_state *state = NULL;
    4758          42 :         struct smb2_hnd *ph = NULL;
    4759           0 :         NTSTATUS status;
    4760             : 
    4761          42 :         req = tevent_req_create(mem_ctx, &state,
    4762             :                                 struct cli_smb2_notify_state);
    4763          42 :         if (req == NULL) {
    4764           0 :                 return NULL;
    4765             :         }
    4766             : 
    4767          42 :         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
    4768          42 :         if (tevent_req_nterror(req, status)) {
    4769           0 :                 return tevent_req_post(req, ev);
    4770             :         }
    4771             : 
    4772          84 :         state->subreq = smb2cli_notify_send(
    4773             :                 state,
    4774             :                 ev,
    4775             :                 cli->conn,
    4776          42 :                 cli->timeout,
    4777             :                 cli->smb2.session,
    4778             :                 cli->smb2.tcon,
    4779             :                 buffer_size,
    4780          42 :                 ph->fid_persistent,
    4781          42 :                 ph->fid_volatile,
    4782             :                 completion_filter,
    4783             :                 recursive);
    4784          42 :         if (tevent_req_nomem(state->subreq, req)) {
    4785           0 :                 return tevent_req_post(req, ev);
    4786             :         }
    4787          42 :         tevent_req_set_callback(state->subreq, cli_smb2_notify_done, req);
    4788          42 :         tevent_req_set_cancel_fn(req, cli_smb2_notify_cancel);
    4789          42 :         return req;
    4790             : }
    4791             : 
    4792           0 : static bool cli_smb2_notify_cancel(struct tevent_req *req)
    4793             : {
    4794           0 :         struct cli_smb2_notify_state *state = tevent_req_data(
    4795             :                 req, struct cli_smb2_notify_state);
    4796           0 :         bool ok;
    4797             : 
    4798           0 :         ok = tevent_req_cancel(state->subreq);
    4799           0 :         return ok;
    4800             : }
    4801             : 
    4802          42 : static void cli_smb2_notify_done(struct tevent_req *subreq)
    4803             : {
    4804          42 :         struct tevent_req *req = tevent_req_callback_data(
    4805             :                 subreq, struct tevent_req);
    4806          42 :         struct cli_smb2_notify_state *state = tevent_req_data(
    4807             :                 req, struct cli_smb2_notify_state);
    4808           0 :         uint8_t *base;
    4809           0 :         uint32_t len;
    4810           0 :         uint32_t ofs;
    4811           0 :         NTSTATUS status;
    4812             : 
    4813          42 :         status = smb2cli_notify_recv(subreq, state, &base, &len);
    4814          42 :         TALLOC_FREE(subreq);
    4815             : 
    4816          42 :         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
    4817           0 :                 tevent_req_done(req);
    4818           0 :                 return;
    4819             :         }
    4820          42 :         if (tevent_req_nterror(req, status)) {
    4821          12 :                 return;
    4822             :         }
    4823             : 
    4824          30 :         ofs = 0;
    4825             : 
    4826          30 :         while (len - ofs >= 12) {
    4827           0 :                 struct notify_change *tmp;
    4828           0 :                 struct notify_change *c;
    4829          30 :                 uint32_t next_ofs = IVAL(base, ofs);
    4830          30 :                 uint32_t file_name_length = IVAL(base, ofs+8);
    4831           0 :                 size_t namelen;
    4832           0 :                 bool ok;
    4833             : 
    4834          30 :                 tmp = talloc_realloc(
    4835             :                         state,
    4836             :                         state->changes,
    4837             :                         struct notify_change,
    4838             :                         state->num_changes + 1);
    4839          30 :                 if (tevent_req_nomem(tmp, req)) {
    4840           0 :                         return;
    4841             :                 }
    4842          30 :                 state->changes = tmp;
    4843          30 :                 c = &state->changes[state->num_changes];
    4844          30 :                 state->num_changes += 1;
    4845             : 
    4846          60 :                 if (smb_buffer_oob(len, ofs, next_ofs) ||
    4847          30 :                     smb_buffer_oob(len, ofs+12, file_name_length)) {
    4848           0 :                         tevent_req_nterror(
    4849             :                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
    4850           0 :                         return;
    4851             :                 }
    4852             : 
    4853          30 :                 c->action = IVAL(base, ofs+4);
    4854             : 
    4855          30 :                 ok = convert_string_talloc(
    4856          30 :                         state->changes,
    4857             :                         CH_UTF16LE,
    4858             :                         CH_UNIX,
    4859          30 :                         base + ofs + 12,
    4860             :                         file_name_length,
    4861          30 :                         &c->name,
    4862             :                         &namelen);
    4863          30 :                 if (!ok) {
    4864           0 :                         tevent_req_nterror(
    4865             :                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
    4866           0 :                         return;
    4867             :                 }
    4868             : 
    4869          30 :                 if (next_ofs == 0) {
    4870          30 :                         break;
    4871             :                 }
    4872           0 :                 ofs += next_ofs;
    4873             :         }
    4874             : 
    4875          30 :         tevent_req_done(req);
    4876             : }
    4877             : 
    4878          42 : NTSTATUS cli_smb2_notify_recv(struct tevent_req *req,
    4879             :                               TALLOC_CTX *mem_ctx,
    4880             :                               struct notify_change **pchanges,
    4881             :                               uint32_t *pnum_changes)
    4882             : {
    4883          42 :         struct cli_smb2_notify_state *state = tevent_req_data(
    4884             :                 req, struct cli_smb2_notify_state);
    4885           0 :         NTSTATUS status;
    4886             : 
    4887          42 :         if (tevent_req_is_nterror(req, &status)) {
    4888          12 :                 return status;
    4889             :         }
    4890          30 :         *pchanges = talloc_move(mem_ctx, &state->changes);
    4891          30 :         *pnum_changes = state->num_changes;
    4892          30 :         return NT_STATUS_OK;
    4893             : }
    4894             : 
    4895           0 : NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
    4896             :                          uint32_t buffer_size, uint32_t completion_filter,
    4897             :                          bool recursive, TALLOC_CTX *mem_ctx,
    4898             :                          struct notify_change **pchanges,
    4899             :                          uint32_t *pnum_changes)
    4900             : {
    4901           0 :         TALLOC_CTX *frame = talloc_stackframe();
    4902           0 :         struct tevent_context *ev;
    4903           0 :         struct tevent_req *req;
    4904           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    4905             : 
    4906           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    4907             :                 /*
    4908             :                  * Can't use sync call while an async call is in flight
    4909             :                  */
    4910           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    4911           0 :                 goto fail;
    4912             :         }
    4913           0 :         ev = samba_tevent_context_init(frame);
    4914           0 :         if (ev == NULL) {
    4915           0 :                 goto fail;
    4916             :         }
    4917           0 :         req = cli_smb2_notify_send(
    4918             :                 frame,
    4919             :                 ev,
    4920             :                 cli,
    4921             :                 fnum,
    4922             :                 buffer_size,
    4923             :                 completion_filter,
    4924             :                 recursive);
    4925           0 :         if (req == NULL) {
    4926           0 :                 goto fail;
    4927             :         }
    4928           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    4929           0 :                 goto fail;
    4930             :         }
    4931           0 :         status = cli_smb2_notify_recv(req, mem_ctx, pchanges, pnum_changes);
    4932           0 : fail:
    4933           0 :         TALLOC_FREE(frame);
    4934           0 :         return status;
    4935             : }
    4936             : 
    4937             : struct cli_smb2_fsctl_state {
    4938             :         DATA_BLOB out;
    4939             : };
    4940             : 
    4941             : static void cli_smb2_fsctl_done(struct tevent_req *subreq);
    4942             : 
    4943          70 : struct tevent_req *cli_smb2_fsctl_send(
    4944             :         TALLOC_CTX *mem_ctx,
    4945             :         struct tevent_context *ev,
    4946             :         struct cli_state *cli,
    4947             :         uint16_t fnum,
    4948             :         uint32_t ctl_code,
    4949             :         const DATA_BLOB *in,
    4950             :         uint32_t max_out)
    4951             : {
    4952          70 :         struct tevent_req *req = NULL, *subreq = NULL;
    4953          70 :         struct cli_smb2_fsctl_state *state = NULL;
    4954          70 :         struct smb2_hnd *ph = NULL;
    4955           0 :         NTSTATUS status;
    4956             : 
    4957          70 :         req = tevent_req_create(mem_ctx, &state, struct cli_smb2_fsctl_state);
    4958          70 :         if (req == NULL) {
    4959           0 :                 return NULL;
    4960             :         }
    4961             : 
    4962          70 :         status = map_fnum_to_smb2_handle(cli, fnum, &ph);
    4963          70 :         if (tevent_req_nterror(req, status)) {
    4964           0 :                 return tevent_req_post(req, ev);
    4965             :         }
    4966             : 
    4967          70 :         subreq = smb2cli_ioctl_send(
    4968             :                 state,
    4969             :                 ev,
    4970             :                 cli->conn,
    4971          70 :                 cli->timeout,
    4972             :                 cli->smb2.session,
    4973             :                 cli->smb2.tcon,
    4974          70 :                 ph->fid_persistent,
    4975          70 :                 ph->fid_volatile,
    4976             :                 ctl_code,
    4977             :                 0, /* in_max_input_length */
    4978             :                 in,
    4979             :                 max_out,
    4980             :                 NULL,
    4981             :                 SMB2_IOCTL_FLAG_IS_FSCTL);
    4982             : 
    4983          70 :         if (tevent_req_nomem(subreq, req)) {
    4984           0 :                 return tevent_req_post(req, ev);
    4985             :         }
    4986          70 :         tevent_req_set_callback(subreq, cli_smb2_fsctl_done, req);
    4987          70 :         return req;
    4988             : }
    4989             : 
    4990          70 : static void cli_smb2_fsctl_done(struct tevent_req *subreq)
    4991             : {
    4992          70 :         struct tevent_req *req = tevent_req_callback_data(
    4993             :                 subreq, struct tevent_req);
    4994          70 :         struct cli_smb2_fsctl_state *state = tevent_req_data(
    4995             :                 req, struct cli_smb2_fsctl_state);
    4996           0 :         NTSTATUS status;
    4997             : 
    4998          70 :         status = smb2cli_ioctl_recv(subreq, state, NULL, &state->out);
    4999          70 :         tevent_req_simple_finish_ntstatus(subreq, status);
    5000          70 : }
    5001             : 
    5002          70 : NTSTATUS cli_smb2_fsctl_recv(
    5003             :         struct tevent_req *req, TALLOC_CTX *mem_ctx, DATA_BLOB *out)
    5004             : {
    5005          70 :         struct cli_smb2_fsctl_state *state = tevent_req_data(
    5006             :                 req, struct cli_smb2_fsctl_state);
    5007          70 :         NTSTATUS status = NT_STATUS_OK;
    5008             : 
    5009          70 :         if (tevent_req_is_nterror(req, &status)) {
    5010          50 :                 tevent_req_received(req);
    5011          50 :                 return status;
    5012             :         }
    5013             : 
    5014          20 :         if (state->out.length == 0) {
    5015          20 :                 *out = (DATA_BLOB) { .data = NULL, };
    5016             :         } else {
    5017             :                 /*
    5018             :                  * Can't use talloc_move() here, the outblobs from
    5019             :                  * smb2cli_ioctl_recv() are not standalone talloc
    5020             :                  * objects but just peek into the larger buffers
    5021             :                  * received, hanging off "state".
    5022             :                  */
    5023           0 :                 *out = data_blob_talloc(
    5024             :                         mem_ctx, state->out.data, state->out.length);
    5025           0 :                 if (out->data == NULL) {
    5026           0 :                         status = NT_STATUS_NO_MEMORY;
    5027             :                 }
    5028             :         }
    5029             : 
    5030          20 :         tevent_req_received(req);
    5031          20 :         return NT_STATUS_OK;
    5032             : }

Generated by: LCOV version 1.14