LCOV - code coverage report
Current view: top level - source3/libsmb - cli_smb2_fnum.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 1377 2137 64.4 %
Date: 2021-09-23 10:06:22 Functions: 98 120 81.7 %

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

Generated by: LCOV version 1.13