LCOV - code coverage report
Current view: top level - source3/libsmb - clirap.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 345 750 46.0 %
Date: 2024-06-13 04:01:37 Functions: 22 37 59.5 %

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

Generated by: LCOV version 1.13