LCOV - code coverage report
Current view: top level - source3/libsmb - cli_smb2_fnum.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 1381 2191 63.0 %
Date: 2024-02-28 12:06:22 Functions: 97 116 83.6 %

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

Generated by: LCOV version 1.14