LCOV - code coverage report
Current view: top level - source3/libsmb - clirap.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 467 857 54.5 %
Date: 2024-02-28 12:06:22 Functions: 27 36 75.0 %

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

Generated by: LCOV version 1.14