LCOV - code coverage report
Current view: top level - source3/libsmb - cli_smb2_fnum.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 1177 2109 55.8 %
Date: 2024-06-13 04:01:37 Functions: 85 116 73.3 %

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

Generated by: LCOV version 1.13