LCOV - code coverage report
Current view: top level - source3/libsmb - clirap.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 445 830 53.6 %
Date: 2024-05-31 13:13:24 Functions: 26 35 74.3 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    client RAP calls
       4             :    Copyright (C) Andrew Tridgell         1994-1998
       5             :    Copyright (C) Gerald (Jerry) Carter   2004
       6             :    Copyright (C) James Peach             2007
       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             : #include "includes.h"
      23             : #include "../libcli/auth/libcli_auth.h"
      24             : #include "../librpc/gen_ndr/rap.h"
      25             : #include "../lib/util/tevent_ntstatus.h"
      26             : #include "async_smb.h"
      27             : #include "libsmb/libsmb.h"
      28             : #include "libsmb/clirap.h"
      29             : #include "trans2.h"
      30             : #include "../libcli/smb/smbXcli_base.h"
      31             : #include "libcli/smb/reparse.h"
      32             : #include "cli_smb2_fnum.h"
      33             : #include "lib/util/string_wrappers.h"
      34             : 
      35             : #include <gnutls/gnutls.h>
      36             : #include <gnutls/crypto.h>
      37             : 
      38             : #define PIPE_LANMAN   "\\PIPE\\LANMAN"
      39             : 
      40             : /****************************************************************************
      41             :  Call a remote api
      42             : ****************************************************************************/
      43             : 
      44          56 : bool cli_api(struct cli_state *cli,
      45             :              char *param, int prcnt, int mprcnt,
      46             :              char *data, int drcnt, int mdrcnt,
      47             :              char **rparam, unsigned int *rprcnt,
      48             :              char **rdata, unsigned int *rdrcnt)
      49             : {
      50           0 :         NTSTATUS status;
      51             : 
      52           0 :         uint8_t *my_rparam, *my_rdata;
      53           0 :         uint32_t num_my_rparam, num_my_rdata;
      54             : 
      55          56 :         status = cli_trans(talloc_tos(), cli, SMBtrans,
      56             :                            PIPE_LANMAN, 0, /* name, fid */
      57             :                            0, 0,           /* function, flags */
      58             :                            NULL, 0, 0,     /* setup */
      59             :                            (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
      60             :                            (uint8_t *)data, drcnt, mdrcnt,  /* Data, length, max */
      61             :                            NULL,                 /* recv_flags2 */
      62             :                            NULL, 0, NULL,        /* rsetup */
      63             :                            &my_rparam, 0, &num_my_rparam,
      64             :                            &my_rdata, 0, &num_my_rdata);
      65          56 :         if (!NT_STATUS_IS_OK(status)) {
      66           6 :                 return false;
      67             :         }
      68             : 
      69             :         /*
      70             :          * I know this memcpy massively hurts, but there are just tons
      71             :          * of callers of cli_api that eventually need changing to
      72             :          * talloc
      73             :          */
      74             : 
      75          50 :         *rparam = (char *)smb_memdup(my_rparam, num_my_rparam);
      76          50 :         if (*rparam == NULL) {
      77           0 :                 goto fail;
      78             :         }
      79          50 :         *rprcnt = num_my_rparam;
      80          50 :         TALLOC_FREE(my_rparam);
      81             : 
      82          50 :         *rdata = (char *)smb_memdup(my_rdata, num_my_rdata);
      83          50 :         if (*rdata == NULL) {
      84           9 :                 goto fail;
      85             :         }
      86          41 :         *rdrcnt = num_my_rdata;
      87          41 :         TALLOC_FREE(my_rdata);
      88             : 
      89          41 :         return true;
      90           9 : fail:
      91           9 :         TALLOC_FREE(my_rdata);
      92           9 :         TALLOC_FREE(my_rparam);
      93           9 :         *rparam = NULL;
      94           9 :         *rprcnt = 0;
      95           9 :         *rdata = NULL;
      96           9 :         *rdrcnt = 0;
      97           9 :         return false;
      98             : }
      99             : 
     100             : /****************************************************************************
     101             :  Call a NetShareEnum - try and browse available connections on a host.
     102             : ****************************************************************************/
     103             : 
     104           0 : int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state)
     105             : {
     106           0 :         char *rparam = NULL;
     107           0 :         char *rdata = NULL;
     108           0 :         char *p;
     109           0 :         unsigned int rdrcnt,rprcnt;
     110           0 :         char param[1024];
     111           0 :         int count = -1;
     112           0 :         bool ok;
     113           0 :         int res;
     114             : 
     115             :         /* now send a SMBtrans command with api RNetShareEnum */
     116           0 :         p = param;
     117           0 :         SSVAL(p,0,0); /* api number */
     118           0 :         p += 2;
     119           0 :         strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
     120           0 :         p = skip_string(param,sizeof(param),p);
     121           0 :         strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
     122           0 :         p = skip_string(param,sizeof(param),p);
     123           0 :         SSVAL(p,0,1);
     124             :         /*
     125             :          * Win2k needs a *smaller* buffer than 0xFFFF here -
     126             :          * it returns "out of server memory" with 0xFFFF !!! JRA.
     127             :          */
     128           0 :         SSVAL(p,2,0xFFE0);
     129           0 :         p += 4;
     130             : 
     131           0 :         ok = cli_api(
     132             :                 cli,
     133           0 :                 param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
     134             :                 NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
     135             :                 &rparam, &rprcnt,                /* return params, length */
     136             :                 &rdata, &rdrcnt);                /* return data, length */
     137           0 :         if (!ok) {
     138           0 :                 DEBUG(4,("NetShareEnum failed\n"));
     139           0 :                 goto done;
     140             :         }
     141             : 
     142           0 :         if (rprcnt < 6) {
     143           0 :                 DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
     144           0 :                 goto done;
     145             :         }
     146             : 
     147           0 :         res = rparam? SVAL(rparam,0) : -1;
     148             : 
     149           0 :         if (res == 0 || res == ERRmoredata) {
     150           0 :                 int converter=SVAL(rparam,2);
     151           0 :                 int i;
     152           0 :                 char *rdata_end = rdata + rdrcnt;
     153             : 
     154           0 :                 count=SVAL(rparam,4);
     155           0 :                 p = rdata;
     156             : 
     157           0 :                 for (i=0;i<count;i++,p+=20) {
     158           0 :                         char *sname;
     159           0 :                         int type;
     160           0 :                         int comment_offset;
     161           0 :                         const char *cmnt;
     162           0 :                         const char *p1;
     163           0 :                         char *s1, *s2;
     164           0 :                         size_t len;
     165           0 :                         TALLOC_CTX *frame = talloc_stackframe();
     166             : 
     167           0 :                         if (p + 20 > rdata_end) {
     168           0 :                                 TALLOC_FREE(frame);
     169           0 :                                 break;
     170             :                         }
     171             : 
     172           0 :                         sname = p;
     173           0 :                         type = SVAL(p,14);
     174           0 :                         comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
     175           0 :                         if (comment_offset < 0 ||
     176           0 :                             comment_offset > (int)rdrcnt) {
     177           0 :                                 TALLOC_FREE(frame);
     178           0 :                                 break;
     179             :                         }
     180           0 :                         cmnt = comment_offset?(rdata+comment_offset):"";
     181             : 
     182             :                         /* Work out the comment length. */
     183           0 :                         for (p1 = cmnt, len = 0; *p1 &&
     184           0 :                                      p1 < rdata_end; len++)
     185           0 :                                 p1++;
     186           0 :                         if (!*p1) {
     187           0 :                                 len++;
     188             :                         }
     189           0 :                         pull_string_talloc(frame,rdata,0,
     190             :                                            &s1,sname,14,STR_ASCII);
     191           0 :                         pull_string_talloc(frame,rdata,0,
     192             :                                            &s2,cmnt,len,STR_ASCII);
     193           0 :                         if (!s1 || !s2) {
     194           0 :                                 TALLOC_FREE(frame);
     195           0 :                                 continue;
     196             :                         }
     197             : 
     198           0 :                         fn(s1, type, s2, state);
     199             : 
     200           0 :                         TALLOC_FREE(frame);
     201             :                 }
     202             :         } else {
     203           0 :                         DEBUG(4,("NetShareEnum res=%d\n", res));
     204             :         }
     205             : 
     206           0 : done:
     207           0 :         SAFE_FREE(rparam);
     208           0 :         SAFE_FREE(rdata);
     209             : 
     210           0 :         return count;
     211             : }
     212             : 
     213             : /****************************************************************************
     214             :  Call a NetServerEnum for the specified workgroup and servertype mask.  This
     215             :  function then calls the specified callback function for each name returned.
     216             : 
     217             :  The callback function takes 4 arguments: the machine name, the server type,
     218             :  the comment and a state pointer.
     219             : ****************************************************************************/
     220             : 
     221          52 : bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32_t stype,
     222             :                        void (*fn)(const char *, uint32_t, const char *, void *),
     223             :                        void *state)
     224             : {
     225          52 :         char *rparam = NULL;
     226          52 :         char *rdata = NULL;
     227          52 :         char *rdata_end = NULL;
     228           0 :         unsigned int rdrcnt,rprcnt;
     229           0 :         char *p;
     230           0 :         char param[1024];
     231          52 :         int uLevel = 1;
     232           0 :         size_t len;
     233          52 :         uint32_t func = RAP_NetServerEnum2;
     234          52 :         char *last_entry = NULL;
     235          52 :         int total_cnt = 0;
     236          52 :         int return_cnt = 0;
     237           0 :         int res;
     238             : 
     239          52 :         errno = 0; /* reset */
     240             : 
     241             :         /*
     242             :          * This may take more than one transaction, so we should loop until
     243             :          * we no longer get a more data to process or we have all of the
     244             :          * items.
     245             :          */
     246           0 :         do {
     247             :                 /* send a SMBtrans command with api NetServerEnum */
     248          52 :                 p = param;
     249          52 :                 SIVAL(p,0,func); /* api number */
     250          52 :                 p += 2;
     251             : 
     252          52 :                 if (func == RAP_NetServerEnum3) {
     253           0 :                         strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
     254             :                 } else {
     255          52 :                         strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
     256             :                 }
     257             : 
     258          52 :                 p = skip_string(param, sizeof(param), p);
     259          52 :                 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
     260             : 
     261          52 :                 p = skip_string(param, sizeof(param), p);
     262          52 :                 SSVAL(p,0,uLevel);
     263          52 :                 SSVAL(p,2,CLI_BUFFER_SIZE);
     264          52 :                 p += 4;
     265          52 :                 SIVAL(p,0,stype);
     266          52 :                 p += 4;
     267             : 
     268             :                 /* If we have more data, tell the server where
     269             :                  * to continue from.
     270             :                  */
     271          52 :                 len = push_ascii(p,
     272             :                                 workgroup,
     273          52 :                                 sizeof(param) - PTR_DIFF(p,param) - 1,
     274             :                                 STR_TERMINATE|STR_UPPER);
     275             : 
     276          52 :                 if (len == 0) {
     277           0 :                         SAFE_FREE(last_entry);
     278           0 :                         return false;
     279             :                 }
     280          52 :                 p += len;
     281             : 
     282          52 :                 if (func == RAP_NetServerEnum3) {
     283           0 :                         len = push_ascii(p,
     284             :                                         last_entry ? last_entry : "",
     285           0 :                                         sizeof(param) - PTR_DIFF(p,param) - 1,
     286             :                                         STR_TERMINATE);
     287             : 
     288           0 :                         if (len == 0) {
     289           0 :                                 SAFE_FREE(last_entry);
     290           0 :                                 return false;
     291             :                         }
     292           0 :                         p += len;
     293             :                 }
     294             : 
     295             :                 /* Next time through we need to use the continue api */
     296          52 :                 func = RAP_NetServerEnum3;
     297             : 
     298          52 :                 if (!cli_api(cli,
     299          52 :                         param, PTR_DIFF(p,param), 8, /* params, length, max */
     300             :                         NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
     301             :                             &rparam, &rprcnt, /* return params, return size */
     302             :                             &rdata, &rdrcnt)) { /* return data, return size */
     303             : 
     304             :                         /* break out of the loop on error */
     305          11 :                         res = -1;
     306          11 :                         break;
     307             :                 }
     308             : 
     309          41 :                 rdata_end = rdata + rdrcnt;
     310             : 
     311          41 :                 if (rprcnt < 6) {
     312           0 :                         DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
     313           0 :                         res = -1;
     314           0 :                         break;
     315             :                 }
     316             : 
     317          41 :                 res = rparam ? SVAL(rparam,0) : -1;
     318             : 
     319          41 :                 if (res == 0 || res == ERRmoredata ||
     320           0 :                     (res != -1 && cli_errno(cli) == 0)) {
     321          41 :                         char *sname = NULL;
     322           0 :                         int i, count;
     323          41 :                         int converter=SVAL(rparam,2);
     324             : 
     325             :                         /* Get the number of items returned in this buffer */
     326          41 :                         count = SVAL(rparam, 4);
     327             : 
     328             :                         /* The next field contains the number of items left,
     329             :                          * including those returned in this buffer. So the
     330             :                          * first time through this should contain all of the
     331             :                          * entries.
     332             :                          */
     333          41 :                         if (total_cnt == 0) {
     334          41 :                                 total_cnt = SVAL(rparam, 6);
     335             :                         }
     336             : 
     337             :                         /* Keep track of how many we have read */
     338          41 :                         return_cnt += count;
     339          41 :                         p = rdata;
     340             : 
     341             :                         /* The last name in the previous NetServerEnum reply is
     342             :                          * sent back to server in the NetServerEnum3 request
     343             :                          * (last_entry). The next reply should repeat this entry
     344             :                          * as the first element. We have no proof that this is
     345             :                          * always true, but from traces that seems to be the
     346             :                          * behavior from Window Servers. So first lets do a lot
     347             :                          * of checking, just being paranoid. If the string
     348             :                          * matches then we already saw this entry so skip it.
     349             :                          *
     350             :                          * NOTE: sv1_name field must be null terminated and has
     351             :                          * a max size of 16 (NetBIOS Name).
     352             :                          */
     353          41 :                         if (last_entry && count && p &&
     354           0 :                                 (strncmp(last_entry, p, 16) == 0)) {
     355           0 :                             count -= 1; /* Skip this entry */
     356           0 :                             return_cnt = -1; /* Not part of total, so don't count. */
     357           0 :                             p = rdata + 26; /* Skip the whole record */
     358             :                         }
     359             : 
     360         120 :                         for (i = 0; i < count; i++, p += 26) {
     361           0 :                                 int comment_offset;
     362           0 :                                 const char *cmnt;
     363           0 :                                 const char *p1;
     364           0 :                                 char *s1, *s2;
     365          79 :                                 TALLOC_CTX *frame = talloc_stackframe();
     366           0 :                                 uint32_t entry_stype;
     367             : 
     368          79 :                                 if (p + 26 > rdata_end) {
     369           0 :                                         TALLOC_FREE(frame);
     370           0 :                                         break;
     371             :                                 }
     372             : 
     373          79 :                                 sname = p;
     374          79 :                                 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
     375          79 :                                 cmnt = comment_offset?(rdata+comment_offset):"";
     376             : 
     377          79 :                                 if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
     378           0 :                                         TALLOC_FREE(frame);
     379           0 :                                         continue;
     380             :                                 }
     381             : 
     382             :                                 /* Work out the comment length. */
     383        1308 :                                 for (p1 = cmnt, len = 0; *p1 &&
     384        1229 :                                                 p1 < rdata_end; len++)
     385        1229 :                                         p1++;
     386          79 :                                 if (!*p1) {
     387          79 :                                         len++;
     388             :                                 }
     389             : 
     390          79 :                                 entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
     391             : 
     392          79 :                                 pull_string_talloc(frame,rdata,0,
     393             :                                         &s1,sname,16,STR_ASCII);
     394          79 :                                 pull_string_talloc(frame,rdata,0,
     395             :                                         &s2,cmnt,len,STR_ASCII);
     396             : 
     397          79 :                                 if (!s1 || !s2) {
     398           0 :                                         TALLOC_FREE(frame);
     399           0 :                                         continue;
     400             :                                 }
     401             : 
     402          79 :                                 fn(s1, entry_stype, s2, state);
     403          79 :                                 TALLOC_FREE(frame);
     404             :                         }
     405             : 
     406             :                         /* We are done with the old last entry, so now we can free it */
     407          41 :                         if (last_entry) {
     408           0 :                                 SAFE_FREE(last_entry); /* This will set it to null */
     409             :                         }
     410             : 
     411             :                         /* We always make a copy of  the last entry if we have one */
     412          41 :                         if (sname) {
     413          41 :                                 last_entry = smb_xstrdup(sname);
     414             :                         }
     415             : 
     416             :                         /* If we have more data, but no last entry then error out */
     417          41 :                         if (!last_entry && (res == ERRmoredata)) {
     418           0 :                                 errno = EINVAL;
     419           0 :                                 res = 0;
     420             :                         }
     421             : 
     422             :                 }
     423             : 
     424          41 :                 SAFE_FREE(rparam);
     425          41 :                 SAFE_FREE(rdata);
     426          41 :         } while ((res == ERRmoredata) && (total_cnt > return_cnt));
     427             : 
     428          52 :         SAFE_FREE(rparam);
     429          52 :         SAFE_FREE(rdata);
     430          52 :         SAFE_FREE(last_entry);
     431             : 
     432          52 :         if (res == -1) {
     433          11 :                 errno = cli_errno(cli);
     434             :         } else {
     435          41 :                 if (!return_cnt) {
     436             :                         /* this is a very special case, when the domain master for the
     437             :                            work group isn't part of the work group itself, there is something
     438             :                            wild going on */
     439           0 :                         errno = ENOENT;
     440             :                 }
     441             :             }
     442             : 
     443          52 :         return(return_cnt > 0);
     444             : }
     445             : 
     446             : /****************************************************************************
     447             :  Send a SamOEMChangePassword command.
     448             : ****************************************************************************/
     449             : 
     450           0 : bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
     451             :                              const char *old_password)
     452             : {
     453           0 :         char param[1024];
     454           0 :         unsigned char data[532];
     455           0 :         char *p = param;
     456           0 :         unsigned char old_pw_hash[16];
     457           0 :         unsigned char new_pw_hash[16];
     458           0 :         unsigned int data_len;
     459           0 :         unsigned int param_len = 0;
     460           0 :         char *rparam = NULL;
     461           0 :         char *rdata = NULL;
     462           0 :         unsigned int rprcnt, rdrcnt;
     463           0 :         gnutls_cipher_hd_t cipher_hnd = NULL;
     464           0 :         gnutls_datum_t old_pw_key = {
     465             :                 .data = old_pw_hash,
     466             :                 .size = sizeof(old_pw_hash),
     467             :         };
     468           0 :         int rc;
     469             : 
     470           0 :         if (strlen(user) >= sizeof(fstring)-1) {
     471           0 :                 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
     472           0 :                 return False;
     473             :         }
     474             : 
     475           0 :         SSVAL(p,0,214); /* SamOEMChangePassword command. */
     476           0 :         p += 2;
     477           0 :         strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
     478           0 :         p = skip_string(param,sizeof(param),p);
     479           0 :         strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
     480           0 :         p = skip_string(param,sizeof(param),p);
     481           0 :         strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
     482           0 :         p = skip_string(param,sizeof(param),p);
     483           0 :         SSVAL(p,0,532);
     484           0 :         p += 2;
     485             : 
     486           0 :         param_len = PTR_DIFF(p,param);
     487             : 
     488             :         /*
     489             :          * Get the Lanman hash of the old password, we
     490             :          * use this as the key to make_oem_passwd_hash().
     491             :          */
     492           0 :         E_deshash(old_password, old_pw_hash);
     493             : 
     494           0 :         encode_pw_buffer(data, new_password, STR_ASCII);
     495             : 
     496             : #ifdef DEBUG_PASSWORD
     497           0 :         DEBUG(100,("make_oem_passwd_hash\n"));
     498           0 :         dump_data(100, data, 516);
     499             : #endif
     500           0 :         rc = gnutls_cipher_init(&cipher_hnd,
     501             :                                 GNUTLS_CIPHER_ARCFOUR_128,
     502             :                                 &old_pw_key,
     503             :                                 NULL);
     504           0 :         if (rc < 0) {
     505           0 :                 DBG_ERR("gnutls_cipher_init failed: %s\n",
     506             :                         gnutls_strerror(rc));
     507           0 :                 return false;
     508             :         }
     509           0 :         rc = gnutls_cipher_encrypt(cipher_hnd,
     510             :                               data,
     511             :                               516);
     512           0 :         gnutls_cipher_deinit(cipher_hnd);
     513           0 :         if (rc < 0) {
     514           0 :                 return false;
     515             :         }
     516             : 
     517             :         /*
     518             :          * Now place the old password hash in the data.
     519             :          */
     520           0 :         E_deshash(new_password, new_pw_hash);
     521             : 
     522           0 :         rc = E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
     523           0 :         if (rc != 0) {
     524           0 :                 DBG_ERR("E_old_pw_hash failed: %s\n", gnutls_strerror(rc));
     525           0 :                 return false;
     526             :         }
     527             : 
     528           0 :         data_len = 532;
     529             : 
     530           0 :         if (!cli_api(cli,
     531             :                      param, param_len, 4,               /* param, length, max */
     532             :                      (char *)data, data_len, 0,         /* data, length, max */
     533             :                      &rparam, &rprcnt,
     534             :                      &rdata, &rdrcnt)) {
     535           0 :                 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
     536             :                         user ));
     537           0 :                 return False;
     538             :         }
     539             : 
     540           0 :         if (rdrcnt < 2) {
     541           0 :                 cli->rap_error = ERRbadformat;
     542           0 :                 goto done;
     543             :         }
     544             : 
     545           0 :         if (rparam) {
     546           0 :                 cli->rap_error = SVAL(rparam,0);
     547             :         }
     548             : 
     549           0 : done:
     550           0 :         SAFE_FREE(rparam);
     551           0 :         SAFE_FREE(rdata);
     552             : 
     553           0 :         return (cli->rap_error == 0);
     554             : }
     555             : 
     556          44 : static void prep_basic_information_buf(
     557             :         uint8_t buf[40],
     558             :         struct timespec create_time,
     559             :         struct timespec access_time,
     560             :         struct timespec write_time,
     561             :         struct timespec change_time,
     562             :         uint32_t attr)
     563             : {
     564          44 :         char *p = (char *)buf;
     565             :         /*
     566             :          * Add the create, last access, modification, and status change times
     567             :          */
     568          44 :         put_long_date_full_timespec(
     569             :                 TIMESTAMP_SET_NT_OR_BETTER, p, &create_time);
     570          44 :         p += 8;
     571             : 
     572          44 :         put_long_date_full_timespec(
     573             :                 TIMESTAMP_SET_NT_OR_BETTER, p, &access_time);
     574          44 :         p += 8;
     575             : 
     576          44 :         put_long_date_full_timespec(
     577             :                 TIMESTAMP_SET_NT_OR_BETTER, p, &write_time);
     578          44 :         p += 8;
     579             : 
     580          44 :         put_long_date_full_timespec(
     581             :                 TIMESTAMP_SET_NT_OR_BETTER, p, &change_time);
     582          44 :         p += 8;
     583             : 
     584          44 :         if (attr == (uint32_t)-1 || attr == FILE_ATTRIBUTE_NORMAL) {
     585             :                 /* No change. */
     586          30 :                 attr = 0;
     587          14 :         } else if (attr == 0) {
     588             :                 /* Clear all existing attributes. */
     589           9 :                 attr = FILE_ATTRIBUTE_NORMAL;
     590             :         }
     591             : 
     592             :         /* Add attributes */
     593          44 :         SIVAL(p, 0, attr);
     594             : 
     595          44 :         p += 4;
     596             : 
     597             :         /* Add padding */
     598          44 :         SIVAL(p, 0, 0);
     599          44 :         p += 4;
     600             : 
     601          44 :         SMB_ASSERT(PTR_DIFF(p, buf) == 40);
     602          44 : }
     603             : 
     604          44 : NTSTATUS cli_setpathinfo_ext(struct cli_state *cli, const char *fname,
     605             :                              struct timespec create_time,
     606             :                              struct timespec access_time,
     607             :                              struct timespec write_time,
     608             :                              struct timespec change_time,
     609             :                              uint32_t attr)
     610             : {
     611           0 :         uint8_t buf[40];
     612             : 
     613          44 :         prep_basic_information_buf(
     614             :                 buf,
     615             :                 create_time,
     616             :                 access_time,
     617             :                 write_time,
     618             :                 change_time,
     619             :                 attr);
     620             : 
     621          44 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     622          16 :                 DATA_BLOB in_data = data_blob_const(buf, sizeof(buf));
     623             :                 /*
     624             :                  * Split out SMB2 here as we need to select
     625             :                  * the correct info type and level.
     626             :                  */
     627          16 :                 return cli_smb2_setpathinfo(cli,
     628             :                                             fname,
     629             :                                             SMB2_0_INFO_FILE,
     630             :                                             FSCC_FILE_BASIC_INFORMATION,
     631             :                                             &in_data);
     632             :         }
     633             : 
     634          28 :         return cli_setpathinfo(
     635             :                 cli, SMB_FILE_BASIC_INFORMATION, fname, buf, sizeof(buf));
     636             : }
     637             : 
     638             : struct cli_setfileinfo_ext_state {
     639             :         uint8_t data[40];
     640             :         DATA_BLOB in_data;
     641             : };
     642             : 
     643             : static void cli_setfileinfo_ext_done(struct tevent_req *subreq);
     644             : static void cli_setfileinfo_ext_done2(struct tevent_req *subreq);
     645             : 
     646           0 : struct tevent_req *cli_setfileinfo_ext_send(
     647             :         TALLOC_CTX *mem_ctx,
     648             :         struct tevent_context *ev,
     649             :         struct cli_state *cli,
     650             :         uint16_t fnum,
     651             :         struct timespec create_time,
     652             :         struct timespec access_time,
     653             :         struct timespec write_time,
     654             :         struct timespec change_time,
     655             :         uint32_t attr)
     656             : {
     657           0 :         struct tevent_req *req = NULL, *subreq = NULL;
     658           0 :         struct cli_setfileinfo_ext_state *state = NULL;
     659             : 
     660           0 :         req = tevent_req_create(
     661             :                 mem_ctx, &state, struct cli_setfileinfo_ext_state);
     662           0 :         if (req == NULL) {
     663           0 :                 return NULL;
     664             :         }
     665           0 :         prep_basic_information_buf(
     666           0 :                 state->data,
     667             :                 create_time,
     668             :                 access_time,
     669             :                 write_time,
     670             :                 change_time,
     671             :                 attr);
     672             : 
     673           0 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     674           0 :                 state->in_data = (DATA_BLOB) {
     675           0 :                         .data = state->data, .length = sizeof(state->data),
     676             :                 };
     677             : 
     678           0 :                 subreq = cli_smb2_set_info_fnum_send(
     679             :                         state,
     680             :                         ev,
     681             :                         cli,
     682             :                         fnum,
     683             :                         SMB2_0_INFO_FILE,
     684             :                         FSCC_FILE_BASIC_INFORMATION,
     685           0 :                         &state->in_data,
     686             :                         0); /* in_additional_info */
     687           0 :                 if (tevent_req_nomem(subreq, req)) {
     688           0 :                         return tevent_req_post(req, ev);
     689             :                 }
     690           0 :                 tevent_req_set_callback(
     691             :                         subreq, cli_setfileinfo_ext_done2, req);
     692           0 :                 return req;
     693             :         }
     694             : 
     695           0 :         subreq = cli_setfileinfo_send(
     696             :                 state,
     697             :                 ev,
     698             :                 cli,
     699             :                 fnum,
     700             :                 SMB_FILE_BASIC_INFORMATION,
     701           0 :                 state->data,
     702             :                 sizeof(state->data));
     703           0 :         if (tevent_req_nomem(subreq, req)) {
     704           0 :                 return tevent_req_post(req, ev);
     705             :         }
     706           0 :         tevent_req_set_callback(subreq, cli_setfileinfo_ext_done, req);
     707           0 :         return req;
     708             : }
     709             : 
     710           0 : static void cli_setfileinfo_ext_done(struct tevent_req *subreq)
     711             : {
     712           0 :         NTSTATUS status = cli_setfileinfo_recv(subreq);
     713           0 :         tevent_req_simple_finish_ntstatus(subreq, status);
     714           0 : }
     715             : 
     716           0 : static void cli_setfileinfo_ext_done2(struct tevent_req *subreq)
     717             : {
     718           0 :         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
     719           0 :         tevent_req_simple_finish_ntstatus(subreq, status);
     720           0 : }
     721             : 
     722           0 : NTSTATUS cli_setfileinfo_ext_recv(struct tevent_req *req)
     723             : {
     724           0 :         return tevent_req_simple_recv_ntstatus(req);
     725             : }
     726             : 
     727           0 : NTSTATUS cli_setfileinfo_ext(
     728             :         struct cli_state *cli,
     729             :         uint16_t fnum,
     730             :         struct timespec create_time,
     731             :         struct timespec access_time,
     732             :         struct timespec write_time,
     733             :         struct timespec change_time,
     734             :         uint32_t attr)
     735             : {
     736           0 :         TALLOC_CTX *frame = NULL;
     737           0 :         struct tevent_context *ev = NULL;
     738           0 :         struct tevent_req *req = NULL;
     739           0 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     740             : 
     741           0 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
     742             :                 /*
     743             :                  * Can't use sync call while an async call is in flight
     744             :                  */
     745           0 :                 return NT_STATUS_INVALID_PARAMETER;
     746             :         }
     747             : 
     748           0 :         frame = talloc_stackframe();
     749             : 
     750           0 :         ev = samba_tevent_context_init(frame);
     751           0 :         if (ev == NULL) {
     752           0 :                 goto fail;
     753             :         }
     754           0 :         req = cli_setfileinfo_ext_send(
     755             :                 ev,
     756             :                 ev,
     757             :                 cli,
     758             :                 fnum,
     759             :                 create_time,
     760             :                 access_time,
     761             :                 write_time,
     762             :                 change_time,
     763             :                 attr);
     764           0 :         if (req == NULL) {
     765           0 :                 goto fail;
     766             :         }
     767           0 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     768           0 :                 goto fail;
     769             :         }
     770           0 :         status = cli_setfileinfo_ext_recv(req);
     771           0 :  fail:
     772           0 :         TALLOC_FREE(frame);
     773           0 :         return status;
     774             : }
     775             : 
     776             : /****************************************************************************
     777             :  Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
     778             : ****************************************************************************/
     779             : 
     780             : struct cli_qpathinfo2_state {
     781             :         struct tevent_context *ev;
     782             :         struct cli_state *cli;
     783             :         const char *fname;
     784             :         struct timespec create_time;
     785             :         struct timespec access_time;
     786             :         struct timespec write_time;
     787             :         struct timespec change_time;
     788             :         off_t size;
     789             :         uint32_t attr;
     790             :         SMB_INO_T ino;
     791             :         mode_t mode;
     792             : };
     793             : 
     794             : static void cli_qpathinfo2_done2(struct tevent_req *subreq);
     795             : static void cli_qpathinfo2_done(struct tevent_req *subreq);
     796             : static void cli_qpathinfo2_got_reparse(struct tevent_req *subreq);
     797             : 
     798        3057 : struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
     799             :                                        struct tevent_context *ev,
     800             :                                        struct cli_state *cli,
     801             :                                        const char *fname)
     802             : {
     803        3057 :         struct tevent_req *req = NULL, *subreq = NULL;
     804        3057 :         struct cli_qpathinfo2_state *state = NULL;
     805             : 
     806        3057 :         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
     807        3057 :         if (req == NULL) {
     808           0 :                 return NULL;
     809             :         }
     810        3057 :         state->ev = ev;
     811        3057 :         state->cli = cli;
     812        3057 :         state->fname = fname;
     813             : 
     814        3057 :         state->mode = S_IFREG;
     815             : 
     816        3057 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     817        3024 :                 subreq = cli_smb2_qpathinfo_send(state,
     818             :                                                  ev,
     819             :                                                  cli,
     820             :                                                  fname,
     821             :                                                  FSCC_FILE_ALL_INFORMATION,
     822             :                                                  0x60,
     823             :                                                  UINT16_MAX);
     824        3024 :                 if (tevent_req_nomem(subreq, req)) {
     825           0 :                         return tevent_req_post(req, ev);
     826             :                 }
     827        3024 :                 tevent_req_set_callback(subreq, cli_qpathinfo2_done2, req);
     828        3024 :                 return req;
     829             :         }
     830          33 :         subreq = cli_qpathinfo_send(state, ev, cli, fname,
     831             :                                     SMB_QUERY_FILE_ALL_INFO,
     832             :                                     68, CLI_BUFFER_SIZE);
     833          33 :         if (tevent_req_nomem(subreq, req)) {
     834           0 :                 return tevent_req_post(req, ev);
     835             :         }
     836          33 :         tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
     837          33 :         return req;
     838             : }
     839             : 
     840        3024 : static void cli_qpathinfo2_done2(struct tevent_req *subreq)
     841             : {
     842           0 :         struct tevent_req *req =
     843        3024 :                 tevent_req_callback_data(subreq, struct tevent_req);
     844           0 :         struct cli_qpathinfo2_state *state =
     845        3024 :                 tevent_req_data(req, struct cli_qpathinfo2_state);
     846        3024 :         uint8_t *rdata = NULL;
     847           0 :         uint32_t num_rdata;
     848           0 :         NTSTATUS status;
     849             : 
     850        3024 :         status = cli_smb2_qpathinfo_recv(subreq, state, &rdata, &num_rdata);
     851        3024 :         TALLOC_FREE(subreq);
     852        3024 :         if (tevent_req_nterror(req, status)) {
     853         579 :                 return;
     854             :         }
     855        2445 :         state->create_time = interpret_long_date(BVAL(rdata, 0x0));
     856        2445 :         state->access_time = interpret_long_date(BVAL(rdata, 0x8));
     857        2445 :         state->write_time = interpret_long_date(BVAL(rdata, 0x10));
     858        2445 :         state->change_time = interpret_long_date(BVAL(rdata, 0x18));
     859        2445 :         state->attr = PULL_LE_U32(rdata, 0x20);
     860        2445 :         state->size = PULL_LE_U64(rdata, 0x30);
     861        2445 :         state->ino = PULL_LE_U64(rdata, 0x40);
     862             : 
     863        2445 :         if (state->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
     864           0 :                 subreq = cli_get_reparse_data_send(state,
     865             :                                                    state->ev,
     866             :                                                    state->cli,
     867             :                                                    state->fname);
     868           0 :                 if (tevent_req_nomem(subreq, req)) {
     869           0 :                         return;
     870             :                 }
     871           0 :                 tevent_req_set_callback(subreq,
     872             :                                         cli_qpathinfo2_got_reparse,
     873             :                                         req);
     874           0 :                 return;
     875             :         }
     876             : 
     877        2445 :         tevent_req_done(req);
     878             : }
     879             : 
     880          33 : static void cli_qpathinfo2_done(struct tevent_req *subreq)
     881             : {
     882          33 :         struct tevent_req *req = tevent_req_callback_data(
     883             :                 subreq, struct tevent_req);
     884          33 :         struct cli_qpathinfo2_state *state = tevent_req_data(
     885             :                 req, struct cli_qpathinfo2_state);
     886          33 :         uint8_t *data = NULL;
     887           0 :         uint32_t num_data;
     888           0 :         NTSTATUS status;
     889             : 
     890          33 :         status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
     891          33 :         TALLOC_FREE(subreq);
     892          33 :         if (tevent_req_nterror(req, status)) {
     893           2 :                 return;
     894             :         }
     895             : 
     896          31 :         state->create_time = interpret_long_date(BVAL(data, 0));
     897          31 :         state->access_time = interpret_long_date(BVAL(data, 8));
     898          31 :         state->write_time = interpret_long_date(BVAL(data, 16));
     899          31 :         state->change_time = interpret_long_date(BVAL(data, 24));
     900          31 :         state->attr = PULL_LE_U32(data, 32);
     901          31 :         state->size = PULL_LE_U64(data, 48);
     902             : 
     903             :         /*
     904             :          * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO which doesn't
     905             :          * return an inode number (fileid).  We can't change this to
     906             :          * one of the FILE_ID info levels as only Win2003 and above
     907             :          * support these [MS-SMB: 2.2.2.3.1] and the SMB1 code needs
     908             :          * to support older servers.
     909             :          */
     910          31 :         state->ino = 0;
     911             : 
     912          31 :         TALLOC_FREE(data);
     913             : 
     914          31 :         if (state->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
     915           0 :                 subreq = cli_get_reparse_data_send(state,
     916             :                                                    state->ev,
     917             :                                                    state->cli,
     918             :                                                    state->fname);
     919           0 :                 if (tevent_req_nomem(subreq, req)) {
     920           0 :                         return;
     921             :                 }
     922           0 :                 tevent_req_set_callback(subreq,
     923             :                                         cli_qpathinfo2_got_reparse,
     924             :                                         req);
     925           0 :                 return;
     926             :         }
     927             : 
     928          31 :         tevent_req_done(req);
     929             : }
     930             : 
     931           0 : static void cli_qpathinfo2_got_reparse(struct tevent_req *subreq)
     932             : {
     933           0 :         struct tevent_req *req =
     934           0 :                 tevent_req_callback_data(subreq, struct tevent_req);
     935           0 :         struct cli_qpathinfo2_state *state =
     936           0 :                 tevent_req_data(req, struct cli_qpathinfo2_state);
     937           0 :         uint8_t *data = NULL;
     938           0 :         uint32_t num_data;
     939           0 :         struct reparse_data_buffer reparse = {
     940             :                 .tag = 0,
     941             :         };
     942           0 :         NTSTATUS status;
     943             : 
     944           0 :         status = cli_get_reparse_data_recv(subreq, state, &data, &num_data);
     945           0 :         TALLOC_FREE(subreq);
     946           0 :         if (tevent_req_nterror(req, status)) {
     947           0 :                 return;
     948             :         }
     949             : 
     950           0 :         status = reparse_data_buffer_parse(state, &reparse, data, num_data);
     951           0 :         if (!NT_STATUS_IS_OK(status)) {
     952           0 :                 DBG_DEBUG("Ignoring unknown reparse data\n");
     953           0 :                 goto done;
     954             :         }
     955             : 
     956           0 :         switch (reparse.tag) {
     957           0 :         case IO_REPARSE_TAG_SYMLINK:
     958           0 :                 state->mode = S_IFLNK;
     959           0 :                 break;
     960           0 :         case IO_REPARSE_TAG_NFS:
     961           0 :                 switch (reparse.parsed.nfs.type) {
     962           0 :                 case NFS_SPECFILE_LNK:
     963           0 :                         state->mode = S_IFLNK;
     964           0 :                         break;
     965           0 :                 case NFS_SPECFILE_CHR:
     966           0 :                         state->mode = S_IFCHR;
     967           0 :                         break;
     968           0 :                 case NFS_SPECFILE_BLK:
     969           0 :                         state->mode = S_IFBLK;
     970           0 :                         break;
     971           0 :                 case NFS_SPECFILE_FIFO:
     972           0 :                         state->mode = S_IFIFO;
     973           0 :                         break;
     974           0 :                 case NFS_SPECFILE_SOCK:
     975           0 :                         state->mode = S_IFSOCK;
     976           0 :                         break;
     977             :                 }
     978           0 :                 break;
     979             :         }
     980           0 : done:
     981           0 :         tevent_req_done(req);
     982             : }
     983             : 
     984        3057 : NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
     985             :                              struct timespec *create_time,
     986             :                              struct timespec *access_time,
     987             :                              struct timespec *write_time,
     988             :                              struct timespec *change_time,
     989             :                              off_t *size,
     990             :                              uint32_t *pattr,
     991             :                              SMB_INO_T *ino,
     992             :                              mode_t *mode)
     993             : {
     994        3057 :         struct cli_qpathinfo2_state *state = tevent_req_data(
     995             :                 req, struct cli_qpathinfo2_state);
     996           0 :         NTSTATUS status;
     997             : 
     998        3057 :         if (tevent_req_is_nterror(req, &status)) {
     999         581 :                 return status;
    1000             :         }
    1001             : 
    1002        2476 :         if (create_time) {
    1003        2476 :                 *create_time = state->create_time;
    1004             :         }
    1005        2476 :         if (access_time) {
    1006        2468 :                 *access_time = state->access_time;
    1007             :         }
    1008        2476 :         if (write_time) {
    1009        2468 :                 *write_time = state->write_time;
    1010             :         }
    1011        2476 :         if (change_time) {
    1012        2468 :                 *change_time = state->change_time;
    1013             :         }
    1014        2476 :         if (pattr) {
    1015         925 :                 *pattr = state->attr;
    1016             :         }
    1017        2476 :         if (size) {
    1018        2468 :                 *size = state->size;
    1019             :         }
    1020        2476 :         if (ino) {
    1021          25 :                 *ino = state->ino;
    1022             :         }
    1023        2476 :         if (mode != NULL) {
    1024          16 :                 *mode = state->mode;
    1025             :         }
    1026        2476 :         return NT_STATUS_OK;
    1027             : }
    1028             : 
    1029        3057 : NTSTATUS cli_qpathinfo2(struct cli_state *cli,
    1030             :                         const char *fname,
    1031             :                         struct timespec *create_time,
    1032             :                         struct timespec *access_time,
    1033             :                         struct timespec *write_time,
    1034             :                         struct timespec *change_time,
    1035             :                         off_t *size,
    1036             :                         uint32_t *pattr,
    1037             :                         SMB_INO_T *ino,
    1038             :                         mode_t *mode)
    1039             : {
    1040        3057 :         TALLOC_CTX *frame = talloc_stackframe();
    1041        3057 :         struct tevent_context *ev = NULL;
    1042        3057 :         struct tevent_req *req = NULL;
    1043        3057 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1044             : 
    1045        3057 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    1046             :                 /*
    1047             :                  * Can't use sync call while an async call is in flight
    1048             :                  */
    1049           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1050           0 :                 goto fail;
    1051             :         }
    1052        3057 :         ev = samba_tevent_context_init(frame);
    1053        3057 :         if (ev == NULL) {
    1054           0 :                 goto fail;
    1055             :         }
    1056        3057 :         req = cli_qpathinfo2_send(frame, ev, cli, fname);
    1057        3057 :         if (req == NULL) {
    1058           0 :                 goto fail;
    1059             :         }
    1060        3057 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1061           0 :                 goto fail;
    1062             :         }
    1063        3057 :         status = cli_qpathinfo2_recv(req,
    1064             :                                      create_time,
    1065             :                                      access_time,
    1066             :                                      write_time,
    1067             :                                      change_time,
    1068             :                                      size,
    1069             :                                      pattr,
    1070             :                                      ino,
    1071             :                                      mode);
    1072        3057 :  fail:
    1073        3057 :         TALLOC_FREE(frame);
    1074        3057 :         return status;
    1075             : }
    1076             : 
    1077             : /****************************************************************************
    1078             :  Get the stream info
    1079             : ****************************************************************************/
    1080             : 
    1081             : struct cli_qpathinfo_streams_state {
    1082             :         uint32_t num_data;
    1083             :         uint8_t *data;
    1084             : };
    1085             : 
    1086             : static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
    1087             : static void cli_qpathinfo_streams_done2(struct tevent_req *subreq);
    1088             : 
    1089        1681 : struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
    1090             :                                               struct tevent_context *ev,
    1091             :                                               struct cli_state *cli,
    1092             :                                               const char *fname)
    1093             : {
    1094        1681 :         struct tevent_req *req = NULL, *subreq = NULL;
    1095        1681 :         struct cli_qpathinfo_streams_state *state = NULL;
    1096             : 
    1097        1681 :         req = tevent_req_create(mem_ctx, &state,
    1098             :                                 struct cli_qpathinfo_streams_state);
    1099        1681 :         if (req == NULL) {
    1100           0 :                 return NULL;
    1101             :         }
    1102        1681 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
    1103         909 :                 subreq = cli_smb2_qpathinfo_send(state,
    1104             :                                                  ev,
    1105             :                                                  cli,
    1106             :                                                  fname,
    1107             :                                                  FSCC_FILE_STREAM_INFORMATION,
    1108             :                                                  0,
    1109             :                                                  CLI_BUFFER_SIZE);
    1110         909 :                 if (tevent_req_nomem(subreq, req)) {
    1111           0 :                         return tevent_req_post(req, ev);
    1112             :                 }
    1113         909 :                 tevent_req_set_callback(subreq,
    1114             :                                         cli_qpathinfo_streams_done2,
    1115             :                                         req);
    1116         909 :                 return req;
    1117             :         }
    1118         772 :         subreq = cli_qpathinfo_send(state, ev, cli, fname,
    1119             :                                     SMB_FILE_STREAM_INFORMATION,
    1120             :                                     0, CLI_BUFFER_SIZE);
    1121         772 :         if (tevent_req_nomem(subreq, req)) {
    1122           0 :                 return tevent_req_post(req, ev);
    1123             :         }
    1124         772 :         tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
    1125         772 :         return req;
    1126             : }
    1127             : 
    1128         772 : static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
    1129             : {
    1130         772 :         struct tevent_req *req = tevent_req_callback_data(
    1131             :                 subreq, struct tevent_req);
    1132         772 :         struct cli_qpathinfo_streams_state *state = tevent_req_data(
    1133             :                 req, struct cli_qpathinfo_streams_state);
    1134           0 :         NTSTATUS status;
    1135             : 
    1136         772 :         status = cli_qpathinfo_recv(subreq, state, &state->data,
    1137             :                                     &state->num_data);
    1138         772 :         tevent_req_simple_finish_ntstatus(subreq, status);
    1139         772 : }
    1140             : 
    1141         909 : static void cli_qpathinfo_streams_done2(struct tevent_req *subreq)
    1142             : {
    1143           0 :         struct tevent_req *req =
    1144         909 :                 tevent_req_callback_data(subreq, struct tevent_req);
    1145           0 :         struct cli_qpathinfo_streams_state *state =
    1146         909 :                 tevent_req_data(req, struct cli_qpathinfo_streams_state);
    1147           0 :         NTSTATUS status;
    1148             : 
    1149         909 :         status = cli_smb2_qpathinfo_recv(subreq,
    1150             :                                          state,
    1151             :                                          &state->data,
    1152             :                                          &state->num_data);
    1153         909 :         tevent_req_simple_finish_ntstatus(subreq, status);
    1154         909 : }
    1155             : 
    1156        1681 : NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
    1157             :                                     TALLOC_CTX *mem_ctx,
    1158             :                                     unsigned int *pnum_streams,
    1159             :                                     struct stream_struct **pstreams)
    1160             : {
    1161        1681 :         struct cli_qpathinfo_streams_state *state = tevent_req_data(
    1162             :                 req, struct cli_qpathinfo_streams_state);
    1163           0 :         NTSTATUS status;
    1164             : 
    1165        1681 :         if (tevent_req_is_nterror(req, &status)) {
    1166          40 :                 return status;
    1167             :         }
    1168        1641 :         if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
    1169             :                                 pnum_streams, pstreams)) {
    1170           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    1171             :         }
    1172        1641 :         return NT_STATUS_OK;
    1173             : }
    1174             : 
    1175        1681 : NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
    1176             :                                TALLOC_CTX *mem_ctx,
    1177             :                                unsigned int *pnum_streams,
    1178             :                                struct stream_struct **pstreams)
    1179             : {
    1180        1681 :         TALLOC_CTX *frame = NULL;
    1181           0 :         struct tevent_context *ev;
    1182           0 :         struct tevent_req *req;
    1183        1681 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1184             : 
    1185        1681 :         frame = talloc_stackframe();
    1186             : 
    1187        1681 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    1188             :                 /*
    1189             :                  * Can't use sync call while an async call is in flight
    1190             :                  */
    1191           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1192           0 :                 goto fail;
    1193             :         }
    1194        1681 :         ev = samba_tevent_context_init(frame);
    1195        1681 :         if (ev == NULL) {
    1196           0 :                 goto fail;
    1197             :         }
    1198        1681 :         req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
    1199        1681 :         if (req == NULL) {
    1200           0 :                 goto fail;
    1201             :         }
    1202        1681 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1203           0 :                 goto fail;
    1204             :         }
    1205        1681 :         status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
    1206             :                                             pstreams);
    1207        1681 :  fail:
    1208        1681 :         TALLOC_FREE(frame);
    1209        1681 :         return status;
    1210             : }
    1211             : 
    1212        1641 : bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
    1213             :                                size_t data_len,
    1214             :                                unsigned int *pnum_streams,
    1215             :                                struct stream_struct **pstreams)
    1216             : {
    1217           0 :         unsigned int num_streams;
    1218           0 :         struct stream_struct *streams;
    1219           0 :         unsigned int ofs;
    1220             : 
    1221        1641 :         num_streams = 0;
    1222        1641 :         streams = NULL;
    1223        1641 :         ofs = 0;
    1224             : 
    1225        1641 :         while ((data_len > ofs) && (data_len - ofs >= 24)) {
    1226           0 :                 uint32_t nlen, len;
    1227           0 :                 size_t size;
    1228           0 :                 void *vstr;
    1229           0 :                 struct stream_struct *tmp;
    1230           0 :                 uint8_t *tmp_buf;
    1231             : 
    1232        1419 :                 tmp = talloc_realloc(mem_ctx, streams,
    1233             :                                            struct stream_struct,
    1234             :                                            num_streams+1);
    1235             : 
    1236        1419 :                 if (tmp == NULL) {
    1237           0 :                         goto fail;
    1238             :                 }
    1239        1419 :                 streams = tmp;
    1240             : 
    1241        1419 :                 nlen                      = IVAL(rdata, ofs + 0x04);
    1242             : 
    1243        1419 :                 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
    1244             :                         rdata, ofs + 0x08);
    1245        1419 :                 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
    1246             :                         rdata, ofs + 0x10);
    1247             : 
    1248        1419 :                 if (nlen > data_len - (ofs + 24)) {
    1249           0 :                         goto fail;
    1250             :                 }
    1251             : 
    1252             :                 /*
    1253             :                  * We need to null-terminate src, how do I do this with
    1254             :                  * convert_string_talloc??
    1255             :                  */
    1256             : 
    1257        1419 :                 tmp_buf = talloc_array(streams, uint8_t, nlen+2);
    1258        1419 :                 if (tmp_buf == NULL) {
    1259           0 :                         goto fail;
    1260             :                 }
    1261             : 
    1262        1419 :                 memcpy(tmp_buf, rdata+ofs+24, nlen);
    1263        1419 :                 tmp_buf[nlen] = 0;
    1264        1419 :                 tmp_buf[nlen+1] = 0;
    1265             : 
    1266        1419 :                 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
    1267        1419 :                                            nlen+2, &vstr, &size))
    1268             :                 {
    1269           0 :                         TALLOC_FREE(tmp_buf);
    1270           0 :                         goto fail;
    1271             :                 }
    1272             : 
    1273        1419 :                 TALLOC_FREE(tmp_buf);
    1274        1419 :                 streams[num_streams].name = (char *)vstr;
    1275        1419 :                 num_streams++;
    1276             : 
    1277        1419 :                 len = IVAL(rdata, ofs);
    1278        1419 :                 if (len > data_len - ofs) {
    1279           0 :                         goto fail;
    1280             :                 }
    1281        1419 :                 if (len == 0) break;
    1282           0 :                 ofs += len;
    1283             :         }
    1284             : 
    1285        1641 :         *pnum_streams = num_streams;
    1286        1641 :         *pstreams = streams;
    1287        1641 :         return true;
    1288             : 
    1289           0 :  fail:
    1290           0 :         TALLOC_FREE(streams);
    1291           0 :         return false;
    1292             : }
    1293             : 
    1294             : /****************************************************************************
    1295             :  Send a qfileinfo QUERY_FILE_NAME_INFO call.
    1296             : ****************************************************************************/
    1297             : 
    1298             : struct cli_qfileinfo_basic_state {
    1299             :         uint32_t attr;
    1300             :         off_t size;
    1301             :         struct timespec create_time;
    1302             :         struct timespec access_time;
    1303             :         struct timespec write_time;
    1304             :         struct timespec change_time;
    1305             :         SMB_INO_T ino;
    1306             : };
    1307             : 
    1308             : static void cli_qfileinfo_basic_done(struct tevent_req *subreq);
    1309             : static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq);
    1310             : 
    1311        2262 : struct tevent_req *cli_qfileinfo_basic_send(
    1312             :         TALLOC_CTX *mem_ctx,
    1313             :         struct tevent_context *ev,
    1314             :         struct cli_state *cli,
    1315             :         uint16_t fnum)
    1316             : {
    1317        2262 :         struct tevent_req *req = NULL, *subreq = NULL;
    1318        2262 :         struct cli_qfileinfo_basic_state *state = NULL;
    1319             : 
    1320        2262 :         req = tevent_req_create(
    1321             :                 mem_ctx, &state, struct cli_qfileinfo_basic_state);
    1322        2262 :         if (req == NULL) {
    1323           0 :                 return NULL;
    1324             :         }
    1325             : 
    1326        2262 :         if ((smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN2) ||
    1327        2262 :             cli->win95) {
    1328             :                 /*
    1329             :                  * According to
    1330             :                  * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/3d9d8f3e-dc70-410d-a3fc-6f4a881e8cab
    1331             :                  * SMB_COM_TRANSACTION2 used in cli_qfileinfo_send()
    1332             :                  * further down was introduced with the LAN Manager
    1333             :                  * 1.2 dialect, which we encode as PROTOCOL_LANMAN2.
    1334             :                  *
    1335             :                  * The "win95" check was introduced with commit
    1336             :                  * 27e5850fd3e1c8 in 1998. Hard to check these days,
    1337             :                  * but leave it in.
    1338             :                  *
    1339             :                  * Use a lowerlevel fallback in both cases.
    1340             :                  */
    1341             : 
    1342           0 :                 subreq = cli_getattrE_send(state, ev, cli, fnum);
    1343           0 :                 if (tevent_req_nomem(subreq, req)) {
    1344           0 :                         return tevent_req_post(req, ev);
    1345             :                 }
    1346           0 :                 tevent_req_set_callback(
    1347             :                         subreq, cli_qfileinfo_basic_doneE, req);
    1348           0 :                 return req;
    1349             :         }
    1350             : 
    1351        2262 :         subreq = cli_qfileinfo_send(state,
    1352             :                                     ev,
    1353             :                                     cli,
    1354             :                                     fnum,
    1355             :                                     FSCC_FILE_ALL_INFORMATION, /* level */
    1356             :                                     68,                        /* min_rdata */
    1357             :                                     CLI_BUFFER_SIZE);          /* max_rdata */
    1358        2262 :         if (tevent_req_nomem(subreq, req)) {
    1359           0 :                 return tevent_req_post(req, ev);
    1360             :         }
    1361        2262 :         tevent_req_set_callback(subreq, cli_qfileinfo_basic_done, req);
    1362        2262 :         return req;
    1363             : }
    1364             : 
    1365        2262 : static void cli_qfileinfo_basic_done(struct tevent_req *subreq)
    1366             : {
    1367        2262 :         struct tevent_req *req = tevent_req_callback_data(
    1368             :                 subreq, struct tevent_req);
    1369        2262 :         struct cli_qfileinfo_basic_state *state = tevent_req_data(
    1370             :                 req, struct cli_qfileinfo_basic_state);
    1371           0 :         uint8_t *rdata;
    1372           0 :         uint32_t num_rdata;
    1373           0 :         NTSTATUS status;
    1374             : 
    1375        2262 :         status = cli_qfileinfo_recv(
    1376             :                 subreq, state, NULL, &rdata, &num_rdata);
    1377        2262 :         TALLOC_FREE(subreq);
    1378        2262 :         if (tevent_req_nterror(req, status)) {
    1379           0 :                 return;
    1380             :         }
    1381             : 
    1382        2262 :         state->create_time = interpret_long_date(BVAL(rdata, 0));
    1383        2262 :         state->access_time = interpret_long_date(BVAL(rdata, 8));
    1384        2262 :         state->write_time = interpret_long_date(BVAL(rdata, 16));
    1385        2262 :         state->change_time = interpret_long_date(BVAL(rdata, 24));
    1386        2262 :         state->attr = PULL_LE_U32(rdata, 32);
    1387        2262 :         state->size = PULL_LE_U64(rdata,48);
    1388        2262 :         state->ino = PULL_LE_U32(rdata, 64);
    1389        2262 :         TALLOC_FREE(rdata);
    1390             : 
    1391        2262 :         tevent_req_done(req);
    1392             : }
    1393             : 
    1394           0 : static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq)
    1395             : {
    1396           0 :         struct tevent_req *req = tevent_req_callback_data(
    1397             :                 subreq, struct tevent_req);
    1398           0 :         struct cli_qfileinfo_basic_state *state = tevent_req_data(
    1399             :                 req, struct cli_qfileinfo_basic_state);
    1400           0 :         NTSTATUS status;
    1401             : 
    1402           0 :         status = cli_getattrE_recv(
    1403             :                 subreq,
    1404             :                 &state->attr,
    1405             :                 &state->size,
    1406           0 :                 &state->change_time.tv_sec,
    1407           0 :                 &state->access_time.tv_sec,
    1408           0 :                 &state->write_time.tv_sec);
    1409           0 :         TALLOC_FREE(subreq);
    1410           0 :         if (tevent_req_nterror(req, status)) {
    1411           0 :                 return;
    1412             :         }
    1413           0 :         tevent_req_done(req);
    1414             : }
    1415             : 
    1416        2262 : NTSTATUS cli_qfileinfo_basic_recv(
    1417             :         struct tevent_req *req,
    1418             :         uint32_t *attr,
    1419             :         off_t *size,
    1420             :         struct timespec *create_time,
    1421             :         struct timespec *access_time,
    1422             :         struct timespec *write_time,
    1423             :         struct timespec *change_time,
    1424             :         SMB_INO_T *ino)
    1425             : {
    1426        2262 :         struct cli_qfileinfo_basic_state *state = tevent_req_data(
    1427             :                 req, struct cli_qfileinfo_basic_state);
    1428           0 :         NTSTATUS status;
    1429             : 
    1430        2262 :         if (tevent_req_is_nterror(req, &status)) {
    1431           0 :                 return status;
    1432             :         }
    1433             : 
    1434        2262 :         if (create_time != NULL) {
    1435          39 :                 *create_time = state->create_time;
    1436             :         }
    1437        2262 :         if (access_time != NULL) {
    1438          73 :                 *access_time = state->access_time;
    1439             :         }
    1440        2262 :         if (write_time != NULL) {
    1441          73 :                 *write_time = state->write_time;
    1442             :         }
    1443        2262 :         if (change_time != NULL) {
    1444          73 :                 *change_time = state->change_time;
    1445             :         }
    1446        2262 :         if (attr != NULL) {
    1447         814 :                 *attr = state->attr;
    1448             :         }
    1449        2262 :         if (size != NULL) {
    1450        2228 :                 *size = state->size;
    1451             :         }
    1452        2262 :         if (ino) {
    1453          68 :                 *ino = state->ino;
    1454             :         }
    1455             : 
    1456        2262 :         return NT_STATUS_OK;
    1457             : }
    1458             : /****************************************************************************
    1459             :  Send a qfileinfo call.
    1460             : ****************************************************************************/
    1461             : 
    1462         940 : NTSTATUS cli_qfileinfo_basic(
    1463             :         struct cli_state *cli,
    1464             :         uint16_t fnum,
    1465             :         uint32_t *attr,
    1466             :         off_t *size,
    1467             :         struct timespec *create_time,
    1468             :         struct timespec *access_time,
    1469             :         struct timespec *write_time,
    1470             :         struct timespec *change_time,
    1471             :         SMB_INO_T *ino)
    1472             : {
    1473         940 :         TALLOC_CTX *frame = NULL;
    1474         940 :         struct tevent_context *ev = NULL;
    1475         940 :         struct tevent_req *req = NULL;
    1476         940 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1477             : 
    1478         940 :         frame = talloc_stackframe();
    1479             : 
    1480         940 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    1481             :                 /*
    1482             :                  * Can't use sync call while an async call is in flight
    1483             :                  */
    1484           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1485           0 :                 goto fail;
    1486             :         }
    1487         940 :         ev = samba_tevent_context_init(frame);
    1488         940 :         if (ev == NULL) {
    1489           0 :                 goto fail;
    1490             :         }
    1491         940 :         req = cli_qfileinfo_basic_send(frame, ev, cli, fnum);
    1492         940 :         if (req == NULL) {
    1493           0 :                 goto fail;
    1494             :         }
    1495         940 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1496           0 :                 goto fail;
    1497             :         }
    1498             : 
    1499         940 :         status = cli_qfileinfo_basic_recv(
    1500             :                 req,
    1501             :                 attr,
    1502             :                 size,
    1503             :                 create_time,
    1504             :                 access_time,
    1505             :                 write_time,
    1506             :                 change_time,
    1507             :                 ino);
    1508             : 
    1509             :         /* cli_smb2_query_info_fnum_recv doesn't set this */
    1510         940 :         cli->raw_status = status;
    1511         940 : fail:
    1512         940 :         TALLOC_FREE(frame);
    1513         940 :         return status;
    1514             : }
    1515             : 
    1516             : /****************************************************************************
    1517             :  Send a qpathinfo BASIC_INFO call.
    1518             : ****************************************************************************/
    1519             : 
    1520             : struct cli_qpathinfo_basic_state {
    1521             :         uint32_t num_data;
    1522             :         uint8_t *data;
    1523             : };
    1524             : 
    1525             : static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
    1526             : 
    1527        4224 : struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
    1528             :                                             struct tevent_context *ev,
    1529             :                                             struct cli_state *cli,
    1530             :                                             const char *fname)
    1531             : {
    1532        4224 :         struct tevent_req *req = NULL, *subreq = NULL;
    1533        4224 :         struct cli_qpathinfo_basic_state *state = NULL;
    1534             : 
    1535        4224 :         req = tevent_req_create(mem_ctx, &state,
    1536             :                                 struct cli_qpathinfo_basic_state);
    1537        4224 :         if (req == NULL) {
    1538           0 :                 return NULL;
    1539             :         }
    1540        4224 :         subreq = cli_qpathinfo_send(state, ev, cli, fname,
    1541             :                                     SMB_QUERY_FILE_BASIC_INFO,
    1542             :                                     36, CLI_BUFFER_SIZE);
    1543        4224 :         if (tevent_req_nomem(subreq, req)) {
    1544           0 :                 return tevent_req_post(req, ev);
    1545             :         }
    1546        4224 :         tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
    1547        4224 :         return req;
    1548             : }
    1549             : 
    1550        4224 : static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
    1551             : {
    1552        4224 :         struct tevent_req *req = tevent_req_callback_data(
    1553             :                 subreq, struct tevent_req);
    1554        4224 :         struct cli_qpathinfo_basic_state *state = tevent_req_data(
    1555             :                 req, struct cli_qpathinfo_basic_state);
    1556           0 :         NTSTATUS status;
    1557             : 
    1558        4224 :         status = cli_qpathinfo_recv(subreq, state, &state->data,
    1559             :                                     &state->num_data);
    1560        4224 :         TALLOC_FREE(subreq);
    1561        4224 :         if (tevent_req_nterror(req, status)) {
    1562        1816 :                 return;
    1563             :         }
    1564        2408 :         tevent_req_done(req);
    1565             : }
    1566             : 
    1567        4224 : NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
    1568             :                                   SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
    1569             : {
    1570        4224 :         struct cli_qpathinfo_basic_state *state = tevent_req_data(
    1571             :                 req, struct cli_qpathinfo_basic_state);
    1572           0 :         NTSTATUS status;
    1573             : 
    1574        4224 :         if (tevent_req_is_nterror(req, &status)) {
    1575        1816 :                 return status;
    1576             :         }
    1577             : 
    1578        2408 :         sbuf->st_ex_btime = interpret_long_date(BVAL(state->data, 0));
    1579        2408 :         sbuf->st_ex_atime = interpret_long_date(BVAL(state->data, 8));
    1580        2408 :         sbuf->st_ex_mtime = interpret_long_date(BVAL(state->data, 16));
    1581        2408 :         sbuf->st_ex_ctime = interpret_long_date(BVAL(state->data, 24));
    1582        2408 :         *attributes = IVAL(state->data, 32);
    1583        2408 :         return NT_STATUS_OK;
    1584             : }
    1585             : 
    1586       11172 : NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
    1587             :                              SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
    1588             : {
    1589       11172 :         TALLOC_CTX *frame = NULL;
    1590           0 :         struct tevent_context *ev;
    1591           0 :         struct tevent_req *req;
    1592       11172 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
    1593             : 
    1594       11172 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
    1595        6948 :                 return cli_smb2_qpathinfo_basic(cli,
    1596             :                                                 name,
    1597             :                                                 sbuf,
    1598             :                                                 attributes);
    1599             :         }
    1600             : 
    1601        4224 :         frame = talloc_stackframe();
    1602             : 
    1603        4224 :         if (smbXcli_conn_has_async_calls(cli->conn)) {
    1604             :                 /*
    1605             :                  * Can't use sync call while an async call is in flight
    1606             :                  */
    1607           0 :                 status = NT_STATUS_INVALID_PARAMETER;
    1608           0 :                 goto fail;
    1609             :         }
    1610        4224 :         ev = samba_tevent_context_init(frame);
    1611        4224 :         if (ev == NULL) {
    1612           0 :                 goto fail;
    1613             :         }
    1614        4224 :         req = cli_qpathinfo_basic_send(frame, ev, cli, name);
    1615        4224 :         if (req == NULL) {
    1616           0 :                 goto fail;
    1617             :         }
    1618        4224 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
    1619           0 :                 goto fail;
    1620             :         }
    1621        4224 :         status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
    1622        4224 :  fail:
    1623        4224 :         TALLOC_FREE(frame);
    1624        4224 :         return status;
    1625             : }
    1626             : 
    1627             : /****************************************************************************
    1628             :  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
    1629             : ****************************************************************************/
    1630             : 
    1631        1737 : NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
    1632             : {
    1633           0 :         uint8_t *rdata;
    1634           0 :         uint32_t num_rdata;
    1635           0 :         unsigned int len;
    1636        1737 :         char *converted = NULL;
    1637        1737 :         size_t converted_size = 0;
    1638           0 :         NTSTATUS status;
    1639             : 
    1640        1737 :         status = cli_qpathinfo(talloc_tos(), cli, fname,
    1641             :                                SMB_QUERY_FILE_ALT_NAME_INFO,
    1642             :                                4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
    1643        1737 :         if (!NT_STATUS_IS_OK(status)) {
    1644          56 :                 return status;
    1645             :         }
    1646             : 
    1647        1681 :         len = IVAL(rdata, 0);
    1648             : 
    1649        1681 :         if (len > num_rdata - 4) {
    1650           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
    1651             :         }
    1652             : 
    1653             :         /* The returned data is a pushed string, not raw data. */
    1654        1681 :         if (!convert_string_talloc(talloc_tos(),
    1655        1681 :                                    smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
    1656             :                                    CH_UNIX,
    1657        1681 :                                    rdata + 4,
    1658             :                                    len,
    1659             :                                    &converted,
    1660             :                                    &converted_size)) {
    1661           0 :                 return NT_STATUS_NO_MEMORY;
    1662             :         }
    1663        1681 :         fstrcpy(alt_name, converted);
    1664             : 
    1665        1681 :         TALLOC_FREE(converted);
    1666        1681 :         TALLOC_FREE(rdata);
    1667             : 
    1668        1681 :         return NT_STATUS_OK;
    1669             : }
    1670             : 
    1671             : /****************************************************************************
    1672             :  Send a qpathinfo SMB_QUERY_FILE_STANDARD_INFO call.
    1673             : ****************************************************************************/
    1674             : 
    1675        2300 : NTSTATUS cli_qpathinfo_standard(struct cli_state *cli, const char *fname,
    1676             :                                 uint64_t *allocated, uint64_t *size,
    1677             :                                 uint32_t *nlinks,
    1678             :                                 bool *is_del_pending, bool *is_dir)
    1679             : {
    1680           0 :         uint8_t *rdata;
    1681           0 :         uint32_t num_rdata;
    1682           0 :         NTSTATUS status;
    1683             : 
    1684        2300 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
    1685           0 :                 return NT_STATUS_NOT_IMPLEMENTED;
    1686             :         }
    1687             : 
    1688        2300 :         status = cli_qpathinfo(talloc_tos(), cli, fname,
    1689             :                                SMB_QUERY_FILE_STANDARD_INFO,
    1690             :                                24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
    1691        2300 :         if (!NT_STATUS_IS_OK(status)) {
    1692           0 :                 return status;
    1693             :         }
    1694             : 
    1695        2300 :         if (allocated) {
    1696           0 :                 *allocated = BVAL(rdata, 0);
    1697             :         }
    1698             : 
    1699        2300 :         if (size) {
    1700        2300 :                 *size = BVAL(rdata, 8);
    1701             :         }
    1702             : 
    1703        2300 :         if (nlinks) {
    1704           0 :                 *nlinks = IVAL(rdata, 16);
    1705             :         }
    1706             : 
    1707        2300 :         if (is_del_pending) {
    1708           0 :                 *is_del_pending = CVAL(rdata, 20);
    1709             :         }
    1710             : 
    1711        2300 :         if (is_dir) {
    1712           0 :                 *is_dir = CVAL(rdata, 20);
    1713             :         }
    1714             : 
    1715        2300 :         TALLOC_FREE(rdata);
    1716             : 
    1717        2300 :         return NT_STATUS_OK;
    1718             : }
    1719             : 
    1720             : 
    1721             : /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
    1722        5890 : NTSTATUS cli_qpathinfo3(struct cli_state *cli, const char *fname,
    1723             :                         struct timespec *create_time,
    1724             :                         struct timespec *access_time,
    1725             :                         struct timespec *write_time,
    1726             :                         struct timespec *change_time,
    1727             :                         off_t *size, uint32_t *pattr,
    1728             :                         SMB_INO_T *ino)
    1729             : {
    1730        5890 :         NTSTATUS status = NT_STATUS_OK;
    1731        5890 :         SMB_STRUCT_STAT st = { 0 };
    1732        5890 :         uint32_t attr = 0;
    1733           0 :         uint64_t pos;
    1734             : 
    1735        5890 :         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
    1736             :                 /*
    1737             :                  * NB. cli_qpathinfo2() checks pattr is valid before
    1738             :                  * storing a value into it, so we don't need to use
    1739             :                  * an intermediate attr variable as below but can
    1740             :                  * pass pattr directly.
    1741             :                  */
    1742        3014 :                 return cli_qpathinfo2(cli,
    1743             :                                       fname,
    1744             :                                       create_time,
    1745             :                                       access_time,
    1746             :                                       write_time,
    1747             :                                       change_time,
    1748             :                                       size,
    1749             :                                       pattr,
    1750             :                                       ino,
    1751             :                                       NULL);
    1752             :         }
    1753             : 
    1754        2876 :         if (create_time || access_time || write_time || change_time || pattr) {
    1755             :                 /*
    1756             :                  * cli_qpathinfo_basic() always indirects the passed
    1757             :                  * in pointers so we use intermediate variables to
    1758             :                  * collect all of them before assigning any requested
    1759             :                  * below.
    1760             :                  */
    1761        2876 :                 status = cli_qpathinfo_basic(cli, fname, &st, &attr);
    1762        2876 :                 if (!NT_STATUS_IS_OK(status)) {
    1763         576 :                         return status;
    1764             :                 }
    1765             :         }
    1766             : 
    1767        2300 :         if (size) {
    1768        2300 :                 status = cli_qpathinfo_standard(cli, fname,
    1769             :                                                 NULL, &pos, NULL, NULL, NULL);
    1770        2300 :                 if (!NT_STATUS_IS_OK(status)) {
    1771           0 :                         return status;
    1772             :                 }
    1773             : 
    1774        2300 :                 *size = pos;
    1775             :         }
    1776             : 
    1777        2300 :         if (create_time) {
    1778        2300 :                 *create_time = st.st_ex_btime;
    1779             :         }
    1780        2300 :         if (access_time) {
    1781        2300 :                 *access_time = st.st_ex_atime;
    1782             :         }
    1783        2300 :         if (write_time) {
    1784        2300 :                 *write_time = st.st_ex_mtime;
    1785             :         }
    1786        2300 :         if (change_time) {
    1787        2300 :                 *change_time = st.st_ex_ctime;
    1788             :         }
    1789        2300 :         if (pattr) {
    1790         772 :                 *pattr = attr;
    1791             :         }
    1792        2300 :         if (ino) {
    1793           0 :                 *ino = 0;
    1794             :         }
    1795             : 
    1796        2300 :         return NT_STATUS_OK;
    1797             : }

Generated by: LCOV version 1.14