LCOV - code coverage report
Current view: top level - source3/libsmb - cli_smb2_fnum.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 1162 2044 56.8 %
Date: 2024-02-14 10:14:15 Functions: 86 116 74.1 %

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

Generated by: LCOV version 1.14