Fix a few "might be uninitialized" errors
[samba.git] / source3 / libsmb / clirap.c
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 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         NTSTATUS status;
51
52         uint8_t *my_rparam, *my_rdata;
53         uint32_t num_my_rparam, num_my_rdata;
54
55         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         if (!NT_STATUS_IS_OK(status)) {
66                 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         *rparam = (char *)smb_memdup(my_rparam, num_my_rparam);
76         if (*rparam == NULL) {
77                 goto fail;
78         }
79         *rprcnt = num_my_rparam;
80         TALLOC_FREE(my_rparam);
81
82         *rdata = (char *)smb_memdup(my_rdata, num_my_rdata);
83         if (*rdata == NULL) {
84                 goto fail;
85         }
86         *rdrcnt = num_my_rdata;
87         TALLOC_FREE(my_rdata);
88
89         return true;
90 fail:
91         TALLOC_FREE(my_rdata);
92         TALLOC_FREE(my_rparam);
93         *rparam = NULL;
94         *rprcnt = 0;
95         *rdata = NULL;
96         *rdrcnt = 0;
97         return false;
98 }
99
100 /****************************************************************************
101  Call a NetShareEnum - try and browse available connections on a host.
102 ****************************************************************************/
103
104 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32_t, const char *, void *), void *state)
105 {
106         char *rparam = NULL;
107         char *rdata = NULL;
108         char *p;
109         unsigned int rdrcnt,rprcnt;
110         char param[1024];
111         int count = -1;
112         bool ok;
113         int res;
114
115         /* now send a SMBtrans command with api RNetShareEnum */
116         p = param;
117         SSVAL(p,0,0); /* api number */
118         p += 2;
119         strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
120         p = skip_string(param,sizeof(param),p);
121         strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
122         p = skip_string(param,sizeof(param),p);
123         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         SSVAL(p,2,0xFFE0);
129         p += 4;
130
131         ok = cli_api(
132                 cli,
133                 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         if (!ok) {
138                 DEBUG(4,("NetShareEnum failed\n"));
139                 goto done;
140         }
141
142         if (rprcnt < 6) {
143                 DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
144                 goto done;
145         }
146
147         res = rparam? SVAL(rparam,0) : -1;
148
149         if (res == 0 || res == ERRmoredata) {
150                 int converter=SVAL(rparam,2);
151                 int i;
152                 char *rdata_end = rdata + rdrcnt;
153
154                 count=SVAL(rparam,4);
155                 p = rdata;
156
157                 for (i=0;i<count;i++,p+=20) {
158                         char *sname;
159                         int type;
160                         int comment_offset;
161                         const char *cmnt;
162                         const char *p1;
163                         char *s1, *s2;
164                         size_t len;
165                         TALLOC_CTX *frame = talloc_stackframe();
166
167                         if (p + 20 > rdata_end) {
168                                 TALLOC_FREE(frame);
169                                 break;
170                         }
171
172                         sname = p;
173                         type = SVAL(p,14);
174                         comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
175                         if (comment_offset < 0 ||
176                             comment_offset > (int)rdrcnt) {
177                                 TALLOC_FREE(frame);
178                                 break;
179                         }
180                         cmnt = comment_offset?(rdata+comment_offset):"";
181
182                         /* Work out the comment length. */
183                         for (p1 = cmnt, len = 0; *p1 &&
184                                      p1 < rdata_end; len++)
185                                 p1++;
186                         if (!*p1) {
187                                 len++;
188                         }
189                         pull_string_talloc(frame,rdata,0,
190                                            &s1,sname,14,STR_ASCII);
191                         pull_string_talloc(frame,rdata,0,
192                                            &s2,cmnt,len,STR_ASCII);
193                         if (!s1 || !s2) {
194                                 TALLOC_FREE(frame);
195                                 continue;
196                         }
197
198                         fn(s1, type, s2, state);
199
200                         TALLOC_FREE(frame);
201                 }
202         } else {
203                         DEBUG(4,("NetShareEnum res=%d\n", res));
204         }
205
206 done:
207         SAFE_FREE(rparam);
208         SAFE_FREE(rdata);
209
210         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 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         char *rparam = NULL;
226         char *rdata = NULL;
227         char *rdata_end = NULL;
228         unsigned int rdrcnt,rprcnt;
229         char *p;
230         char param[1024];
231         int uLevel = 1;
232         size_t len;
233         uint32_t func = RAP_NetServerEnum2;
234         char *last_entry = NULL;
235         int total_cnt = 0;
236         int return_cnt = 0;
237         int res;
238
239         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         do {
247                 /* send a SMBtrans command with api NetServerEnum */
248                 p = param;
249                 SIVAL(p,0,func); /* api number */
250                 p += 2;
251
252                 if (func == RAP_NetServerEnum3) {
253                         strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
254                 } else {
255                         strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
256                 }
257
258                 p = skip_string(param, sizeof(param), p);
259                 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
260
261                 p = skip_string(param, sizeof(param), p);
262                 SSVAL(p,0,uLevel);
263                 SSVAL(p,2,CLI_BUFFER_SIZE);
264                 p += 4;
265                 SIVAL(p,0,stype);
266                 p += 4;
267
268                 /* If we have more data, tell the server where
269                  * to continue from.
270                  */
271                 len = push_ascii(p,
272                                 workgroup,
273                                 sizeof(param) - PTR_DIFF(p,param) - 1,
274                                 STR_TERMINATE|STR_UPPER);
275
276                 if (len == 0) {
277                         SAFE_FREE(last_entry);
278                         return false;
279                 }
280                 p += len;
281
282                 if (func == RAP_NetServerEnum3) {
283                         len = push_ascii(p,
284                                         last_entry ? last_entry : "",
285                                         sizeof(param) - PTR_DIFF(p,param) - 1,
286                                         STR_TERMINATE);
287
288                         if (len == 0) {
289                                 SAFE_FREE(last_entry);
290                                 return false;
291                         }
292                         p += len;
293                 }
294
295                 /* Next time through we need to use the continue api */
296                 func = RAP_NetServerEnum3;
297
298                 if (!cli_api(cli,
299                         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                         res = -1;
306                         break;
307                 }
308
309                 rdata_end = rdata + rdrcnt;
310
311                 if (rprcnt < 6) {
312                         DBG_ERR("Got invalid result: rprcnt=%u\n", rprcnt);
313                         res = -1;
314                         break;
315                 }
316
317                 res = rparam ? SVAL(rparam,0) : -1;
318
319                 if (res == 0 || res == ERRmoredata ||
320                     (res != -1 && cli_errno(cli) == 0)) {
321                         char *sname = NULL;
322                         int i, count;
323                         int converter=SVAL(rparam,2);
324
325                         /* Get the number of items returned in this buffer */
326                         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                         if (total_cnt == 0) {
334                                 total_cnt = SVAL(rparam, 6);
335                         }
336
337                         /* Keep track of how many we have read */
338                         return_cnt += count;
339                         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                         if (last_entry && count && p &&
354                                 (strncmp(last_entry, p, 16) == 0)) {
355                             count -= 1; /* Skip this entry */
356                             return_cnt = -1; /* Not part of total, so don't count. */
357                             p = rdata + 26; /* Skip the whole record */
358                         }
359
360                         for (i = 0; i < count; i++, p += 26) {
361                                 int comment_offset;
362                                 const char *cmnt;
363                                 const char *p1;
364                                 char *s1, *s2;
365                                 TALLOC_CTX *frame = talloc_stackframe();
366                                 uint32_t entry_stype;
367
368                                 if (p + 26 > rdata_end) {
369                                         TALLOC_FREE(frame);
370                                         break;
371                                 }
372
373                                 sname = p;
374                                 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
375                                 cmnt = comment_offset?(rdata+comment_offset):"";
376
377                                 if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
378                                         TALLOC_FREE(frame);
379                                         continue;
380                                 }
381
382                                 /* Work out the comment length. */
383                                 for (p1 = cmnt, len = 0; *p1 &&
384                                                 p1 < rdata_end; len++)
385                                         p1++;
386                                 if (!*p1) {
387                                         len++;
388                                 }
389
390                                 entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
391
392                                 pull_string_talloc(frame,rdata,0,
393                                         &s1,sname,16,STR_ASCII);
394                                 pull_string_talloc(frame,rdata,0,
395                                         &s2,cmnt,len,STR_ASCII);
396
397                                 if (!s1 || !s2) {
398                                         TALLOC_FREE(frame);
399                                         continue;
400                                 }
401
402                                 fn(s1, entry_stype, s2, state);
403                                 TALLOC_FREE(frame);
404                         }
405
406                         /* We are done with the old last entry, so now we can free it */
407                         if (last_entry) {
408                                 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                         if (sname) {
413                                 last_entry = smb_xstrdup(sname);
414                         }
415
416                         /* If we have more data, but no last entry then error out */
417                         if (!last_entry && (res == ERRmoredata)) {
418                                 errno = EINVAL;
419                                 res = 0;
420                         }
421
422                 }
423
424                 SAFE_FREE(rparam);
425                 SAFE_FREE(rdata);
426         } while ((res == ERRmoredata) && (total_cnt > return_cnt));
427
428         SAFE_FREE(rparam);
429         SAFE_FREE(rdata);
430         SAFE_FREE(last_entry);
431
432         if (res == -1) {
433                 errno = cli_errno(cli);
434         } else {
435                 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                         errno = ENOENT;
440                 }
441             }
442
443         return(return_cnt > 0);
444 }
445
446 /****************************************************************************
447  Send a SamOEMChangePassword command.
448 ****************************************************************************/
449
450 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
451                              const char *old_password)
452 {
453         char param[1024];
454         unsigned char data[532];
455         char *p = param;
456         unsigned char old_pw_hash[16];
457         unsigned char new_pw_hash[16];
458         unsigned int data_len;
459         unsigned int param_len = 0;
460         char *rparam = NULL;
461         char *rdata = NULL;
462         unsigned int rprcnt, rdrcnt;
463         gnutls_cipher_hd_t cipher_hnd = NULL;
464         gnutls_datum_t old_pw_key = {
465                 .data = old_pw_hash,
466                 .size = sizeof(old_pw_hash),
467         };
468         int rc;
469
470         if (strlen(user) >= sizeof(fstring)-1) {
471                 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
472                 return False;
473         }
474
475         SSVAL(p,0,214); /* SamOEMChangePassword command. */
476         p += 2;
477         strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
478         p = skip_string(param,sizeof(param),p);
479         strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
480         p = skip_string(param,sizeof(param),p);
481         strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
482         p = skip_string(param,sizeof(param),p);
483         SSVAL(p,0,532);
484         p += 2;
485
486         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         E_deshash(old_password, old_pw_hash);
493
494         encode_pw_buffer(data, new_password, STR_ASCII);
495
496 #ifdef DEBUG_PASSWORD
497         DEBUG(100,("make_oem_passwd_hash\n"));
498         dump_data(100, data, 516);
499 #endif
500         rc = gnutls_cipher_init(&cipher_hnd,
501                                 GNUTLS_CIPHER_ARCFOUR_128,
502                                 &old_pw_key,
503                                 NULL);
504         if (rc < 0) {
505                 DBG_ERR("gnutls_cipher_init failed: %s\n",
506                         gnutls_strerror(rc));
507                 return false;
508         }
509         rc = gnutls_cipher_encrypt(cipher_hnd,
510                               data,
511                               516);
512         gnutls_cipher_deinit(cipher_hnd);
513         if (rc < 0) {
514                 return false;
515         }
516
517         /*
518          * Now place the old password hash in the data.
519          */
520         E_deshash(new_password, new_pw_hash);
521
522         rc = E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
523         if (rc != 0) {
524                 DBG_ERR("E_old_pw_hash failed: %s\n", gnutls_strerror(rc));
525                 return false;
526         }
527
528         data_len = 532;
529
530         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                 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
536                         user ));
537                 return False;
538         }
539
540         if (rdrcnt < 2) {
541                 cli->rap_error = ERRbadformat;
542                 goto done;
543         }
544
545         if (rparam) {
546                 cli->rap_error = SVAL(rparam,0);
547         }
548
549 done:
550         SAFE_FREE(rparam);
551         SAFE_FREE(rdata);
552
553         return (cli->rap_error == 0);
554 }
555
556 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         char *p = (char *)buf;
565         /*
566          * Add the create, last access, modification, and status change times
567          */
568         put_long_date_full_timespec(
569                 TIMESTAMP_SET_NT_OR_BETTER, p, &create_time);
570         p += 8;
571
572         put_long_date_full_timespec(
573                 TIMESTAMP_SET_NT_OR_BETTER, p, &access_time);
574         p += 8;
575
576         put_long_date_full_timespec(
577                 TIMESTAMP_SET_NT_OR_BETTER, p, &write_time);
578         p += 8;
579
580         put_long_date_full_timespec(
581                 TIMESTAMP_SET_NT_OR_BETTER, p, &change_time);
582         p += 8;
583
584         if (attr == (uint32_t)-1 || attr == FILE_ATTRIBUTE_NORMAL) {
585                 /* No change. */
586                 attr = 0;
587         } else if (attr == 0) {
588                 /* Clear all existing attributes. */
589                 attr = FILE_ATTRIBUTE_NORMAL;
590         }
591
592         /* Add attributes */
593         SIVAL(p, 0, attr);
594
595         p += 4;
596
597         /* Add padding */
598         SIVAL(p, 0, 0);
599         p += 4;
600
601         SMB_ASSERT(PTR_DIFF(p, buf) == 40);
602 }
603
604 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         uint8_t buf[40];
612
613         prep_basic_information_buf(
614                 buf,
615                 create_time,
616                 access_time,
617                 write_time,
618                 change_time,
619                 attr);
620
621         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
622                 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                 return cli_smb2_setpathinfo(cli,
628                                 fname,
629                                 1, /* SMB2_SETINFO_FILE */
630                                 SMB_FILE_BASIC_INFORMATION - 1000,
631                                 &in_data);
632         }
633
634         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 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         struct tevent_req *req = NULL, *subreq = NULL;
658         struct cli_setfileinfo_ext_state *state = NULL;
659
660         req = tevent_req_create(
661                 mem_ctx, &state, struct cli_setfileinfo_ext_state);
662         if (req == NULL) {
663                 return NULL;
664         }
665         prep_basic_information_buf(
666                 state->data,
667                 create_time,
668                 access_time,
669                 write_time,
670                 change_time,
671                 attr);
672
673         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
674                 state->in_data = (DATA_BLOB) {
675                         .data = state->data, .length = sizeof(state->data),
676                 };
677
678                 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                         &state->in_data,
686                         0);     /* in_additional_info */
687                 if (tevent_req_nomem(subreq, req)) {
688                         return tevent_req_post(req, ev);
689                 }
690                 tevent_req_set_callback(
691                         subreq, cli_setfileinfo_ext_done2, req);
692                 return req;
693         }
694
695         subreq = cli_setfileinfo_send(
696                 state,
697                 ev,
698                 cli,
699                 fnum,
700                 SMB_FILE_BASIC_INFORMATION,
701                 state->data,
702                 sizeof(state->data));
703         if (tevent_req_nomem(subreq, req)) {
704                 return tevent_req_post(req, ev);
705         }
706         tevent_req_set_callback(subreq, cli_setfileinfo_ext_done, req);
707         return req;
708 }
709
710 static void cli_setfileinfo_ext_done(struct tevent_req *subreq)
711 {
712         NTSTATUS status = cli_setfileinfo_recv(subreq);
713         tevent_req_simple_finish_ntstatus(subreq, status);
714 }
715
716 static void cli_setfileinfo_ext_done2(struct tevent_req *subreq)
717 {
718         NTSTATUS status = cli_smb2_set_info_fnum_recv(subreq);
719         tevent_req_simple_finish_ntstatus(subreq, status);
720 }
721
722 NTSTATUS cli_setfileinfo_ext_recv(struct tevent_req *req)
723 {
724         return tevent_req_simple_recv_ntstatus(req);
725 }
726
727 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         TALLOC_CTX *frame = NULL;
737         struct tevent_context *ev = NULL;
738         struct tevent_req *req = NULL;
739         NTSTATUS status = NT_STATUS_NO_MEMORY;
740
741         if (smbXcli_conn_has_async_calls(cli->conn)) {
742                 /*
743                  * Can't use sync call while an async call is in flight
744                  */
745                 return NT_STATUS_INVALID_PARAMETER;
746         }
747
748         frame = talloc_stackframe();
749
750         ev = samba_tevent_context_init(frame);
751         if (ev == NULL) {
752                 goto fail;
753         }
754         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         if (req == NULL) {
765                 goto fail;
766         }
767         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
768                 goto fail;
769         }
770         status = cli_setfileinfo_ext_recv(req);
771  fail:
772         TALLOC_FREE(frame);
773         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 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         struct tevent_req *req = NULL, *subreq = NULL;
804         struct cli_qpathinfo2_state *state = NULL;
805
806         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
807         if (req == NULL) {
808                 return NULL;
809         }
810         state->ev = ev;
811         state->cli = cli;
812         state->fname = fname;
813
814         state->mode = S_IFREG;
815
816         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
817                 subreq = cli_smb2_qpathinfo_send(state,
818                                                  ev,
819                                                  cli,
820                                                  fname,
821                                                  FSCC_FILE_ALL_INFORMATION,
822                                                  0x60,
823                                                  UINT16_MAX);
824                 if (tevent_req_nomem(subreq, req)) {
825                         return tevent_req_post(req, ev);
826                 }
827                 tevent_req_set_callback(subreq, cli_qpathinfo2_done2, req);
828                 return req;
829         }
830         subreq = cli_qpathinfo_send(state, ev, cli, fname,
831                                     SMB_QUERY_FILE_ALL_INFO,
832                                     68, CLI_BUFFER_SIZE);
833         if (tevent_req_nomem(subreq, req)) {
834                 return tevent_req_post(req, ev);
835         }
836         tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
837         return req;
838 }
839
840 static void cli_qpathinfo2_done2(struct tevent_req *subreq)
841 {
842         struct tevent_req *req =
843                 tevent_req_callback_data(subreq, struct tevent_req);
844         struct cli_qpathinfo2_state *state =
845                 tevent_req_data(req, struct cli_qpathinfo2_state);
846         uint8_t *rdata = NULL;
847         uint32_t num_rdata;
848         NTSTATUS status;
849
850         status = cli_smb2_qpathinfo_recv(subreq, state, &rdata, &num_rdata);
851         TALLOC_FREE(subreq);
852         if (tevent_req_nterror(req, status)) {
853                 return;
854         }
855         state->create_time = interpret_long_date(BVAL(rdata, 0x0));
856         state->access_time = interpret_long_date(BVAL(rdata, 0x8));
857         state->write_time = interpret_long_date(BVAL(rdata, 0x10));
858         state->change_time = interpret_long_date(BVAL(rdata, 0x18));
859         state->attr = PULL_LE_U32(rdata, 0x20);
860         state->size = PULL_LE_U64(rdata, 0x30);
861         state->ino = PULL_LE_U64(rdata, 0x40);
862
863         if (state->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
864                 subreq = cli_get_reparse_data_send(state,
865                                                    state->ev,
866                                                    state->cli,
867                                                    state->fname);
868                 if (tevent_req_nomem(subreq, req)) {
869                         return;
870                 }
871                 tevent_req_set_callback(subreq,
872                                         cli_qpathinfo2_got_reparse,
873                                         req);
874                 return;
875         }
876
877         tevent_req_done(req);
878 }
879
880 static void cli_qpathinfo2_done(struct tevent_req *subreq)
881 {
882         struct tevent_req *req = tevent_req_callback_data(
883                 subreq, struct tevent_req);
884         struct cli_qpathinfo2_state *state = tevent_req_data(
885                 req, struct cli_qpathinfo2_state);
886         uint8_t *data = NULL;
887         uint32_t num_data;
888         NTSTATUS status;
889
890         status = cli_qpathinfo_recv(subreq, state, &data, &num_data);
891         TALLOC_FREE(subreq);
892         if (tevent_req_nterror(req, status)) {
893                 return;
894         }
895
896         state->create_time = interpret_long_date(BVAL(data, 0));
897         state->access_time = interpret_long_date(BVAL(data, 8));
898         state->write_time = interpret_long_date(BVAL(data, 16));
899         state->change_time = interpret_long_date(BVAL(data, 24));
900         state->attr = PULL_LE_U32(data, 32);
901         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         state->ino = 0;
911
912         TALLOC_FREE(data);
913
914         if (state->attr & FILE_ATTRIBUTE_REPARSE_POINT) {
915                 subreq = cli_get_reparse_data_send(state,
916                                                    state->ev,
917                                                    state->cli,
918                                                    state->fname);
919                 if (tevent_req_nomem(subreq, req)) {
920                         return;
921                 }
922                 tevent_req_set_callback(subreq,
923                                         cli_qpathinfo2_got_reparse,
924                                         req);
925                 return;
926         }
927
928         tevent_req_done(req);
929 }
930
931 static void cli_qpathinfo2_got_reparse(struct tevent_req *subreq)
932 {
933         struct tevent_req *req =
934                 tevent_req_callback_data(subreq, struct tevent_req);
935         struct cli_qpathinfo2_state *state =
936                 tevent_req_data(req, struct cli_qpathinfo2_state);
937         uint8_t *data = NULL;
938         uint32_t num_data;
939         struct reparse_data_buffer reparse = {
940                 .tag = 0,
941         };
942         NTSTATUS status;
943
944         status = cli_get_reparse_data_recv(subreq, state, &data, &num_data);
945         TALLOC_FREE(subreq);
946         if (tevent_req_nterror(req, status)) {
947                 return;
948         }
949
950         status = reparse_data_buffer_parse(state, &reparse, data, num_data);
951         if (!NT_STATUS_IS_OK(status)) {
952                 DBG_DEBUG("Ignoring unknown reparse data\n");
953                 goto done;
954         }
955
956         switch (reparse.tag) {
957         case IO_REPARSE_TAG_SYMLINK:
958                 state->mode = S_IFLNK;
959                 break;
960         case IO_REPARSE_TAG_NFS:
961                 switch (reparse.parsed.nfs.type) {
962                 case NFS_SPECFILE_LNK:
963                         state->mode = S_IFLNK;
964                         break;
965                 case NFS_SPECFILE_CHR:
966                         state->mode = S_IFCHR;
967                         break;
968                 case NFS_SPECFILE_BLK:
969                         state->mode = S_IFBLK;
970                         break;
971                 case NFS_SPECFILE_FIFO:
972                         state->mode = S_IFIFO;
973                         break;
974                 case NFS_SPECFILE_SOCK:
975                         state->mode = S_IFSOCK;
976                         break;
977                 }
978                 break;
979         }
980 done:
981         tevent_req_done(req);
982 }
983
984 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         struct cli_qpathinfo2_state *state = tevent_req_data(
995                 req, struct cli_qpathinfo2_state);
996         NTSTATUS status;
997
998         if (tevent_req_is_nterror(req, &status)) {
999                 return status;
1000         }
1001
1002         if (create_time) {
1003                 *create_time = state->create_time;
1004         }
1005         if (access_time) {
1006                 *access_time = state->access_time;
1007         }
1008         if (write_time) {
1009                 *write_time = state->write_time;
1010         }
1011         if (change_time) {
1012                 *change_time = state->change_time;
1013         }
1014         if (pattr) {
1015                 *pattr = state->attr;
1016         }
1017         if (size) {
1018                 *size = state->size;
1019         }
1020         if (ino) {
1021                 *ino = state->ino;
1022         }
1023         if (mode != NULL) {
1024                 *mode = state->mode;
1025         }
1026         return NT_STATUS_OK;
1027 }
1028
1029 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         TALLOC_CTX *frame = talloc_stackframe();
1041         struct tevent_context *ev = NULL;
1042         struct tevent_req *req = NULL;
1043         NTSTATUS status = NT_STATUS_NO_MEMORY;
1044
1045         if (smbXcli_conn_has_async_calls(cli->conn)) {
1046                 /*
1047                  * Can't use sync call while an async call is in flight
1048                  */
1049                 status = NT_STATUS_INVALID_PARAMETER;
1050                 goto fail;
1051         }
1052         ev = samba_tevent_context_init(frame);
1053         if (ev == NULL) {
1054                 goto fail;
1055         }
1056         req = cli_qpathinfo2_send(frame, ev, cli, fname);
1057         if (req == NULL) {
1058                 goto fail;
1059         }
1060         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1061                 goto fail;
1062         }
1063         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  fail:
1073         TALLOC_FREE(frame);
1074         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 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         struct tevent_req *req = NULL, *subreq = NULL;
1095         struct cli_qpathinfo_streams_state *state = NULL;
1096
1097         req = tevent_req_create(mem_ctx, &state,
1098                                 struct cli_qpathinfo_streams_state);
1099         if (req == NULL) {
1100                 return NULL;
1101         }
1102         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1103                 subreq = cli_smb2_qpathinfo_send(state,
1104                                                  ev,
1105                                                  cli,
1106                                                  fname,
1107                                                  FSCC_FILE_STREAM_INFORMATION,
1108                                                  0,
1109                                                  CLI_BUFFER_SIZE);
1110                 if (tevent_req_nomem(subreq, req)) {
1111                         return tevent_req_post(req, ev);
1112                 }
1113                 tevent_req_set_callback(subreq,
1114                                         cli_qpathinfo_streams_done2,
1115                                         req);
1116                 return req;
1117         }
1118         subreq = cli_qpathinfo_send(state, ev, cli, fname,
1119                                     SMB_FILE_STREAM_INFORMATION,
1120                                     0, CLI_BUFFER_SIZE);
1121         if (tevent_req_nomem(subreq, req)) {
1122                 return tevent_req_post(req, ev);
1123         }
1124         tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
1125         return req;
1126 }
1127
1128 static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
1129 {
1130         struct tevent_req *req = tevent_req_callback_data(
1131                 subreq, struct tevent_req);
1132         struct cli_qpathinfo_streams_state *state = tevent_req_data(
1133                 req, struct cli_qpathinfo_streams_state);
1134         NTSTATUS status;
1135
1136         status = cli_qpathinfo_recv(subreq, state, &state->data,
1137                                     &state->num_data);
1138         tevent_req_simple_finish_ntstatus(subreq, status);
1139 }
1140
1141 static void cli_qpathinfo_streams_done2(struct tevent_req *subreq)
1142 {
1143         struct tevent_req *req =
1144                 tevent_req_callback_data(subreq, struct tevent_req);
1145         struct cli_qpathinfo_streams_state *state =
1146                 tevent_req_data(req, struct cli_qpathinfo_streams_state);
1147         NTSTATUS status;
1148
1149         status = cli_smb2_qpathinfo_recv(subreq,
1150                                          state,
1151                                          &state->data,
1152                                          &state->num_data);
1153         tevent_req_simple_finish_ntstatus(subreq, status);
1154 }
1155
1156 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         struct cli_qpathinfo_streams_state *state = tevent_req_data(
1162                 req, struct cli_qpathinfo_streams_state);
1163         NTSTATUS status;
1164
1165         if (tevent_req_is_nterror(req, &status)) {
1166                 return status;
1167         }
1168         if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
1169                                 pnum_streams, pstreams)) {
1170                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1171         }
1172         return NT_STATUS_OK;
1173 }
1174
1175 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         TALLOC_CTX *frame = NULL;
1181         struct tevent_context *ev;
1182         struct tevent_req *req;
1183         NTSTATUS status = NT_STATUS_NO_MEMORY;
1184
1185         frame = talloc_stackframe();
1186
1187         if (smbXcli_conn_has_async_calls(cli->conn)) {
1188                 /*
1189                  * Can't use sync call while an async call is in flight
1190                  */
1191                 status = NT_STATUS_INVALID_PARAMETER;
1192                 goto fail;
1193         }
1194         ev = samba_tevent_context_init(frame);
1195         if (ev == NULL) {
1196                 goto fail;
1197         }
1198         req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
1199         if (req == NULL) {
1200                 goto fail;
1201         }
1202         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1203                 goto fail;
1204         }
1205         status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
1206                                             pstreams);
1207  fail:
1208         TALLOC_FREE(frame);
1209         return status;
1210 }
1211
1212 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         unsigned int num_streams;
1218         struct stream_struct *streams;
1219         unsigned int ofs;
1220
1221         num_streams = 0;
1222         streams = NULL;
1223         ofs = 0;
1224
1225         while ((data_len > ofs) && (data_len - ofs >= 24)) {
1226                 uint32_t nlen, len;
1227                 size_t size;
1228                 void *vstr;
1229                 struct stream_struct *tmp;
1230                 uint8_t *tmp_buf;
1231
1232                 tmp = talloc_realloc(mem_ctx, streams,
1233                                            struct stream_struct,
1234                                            num_streams+1);
1235
1236                 if (tmp == NULL) {
1237                         goto fail;
1238                 }
1239                 streams = tmp;
1240
1241                 nlen                      = IVAL(rdata, ofs + 0x04);
1242
1243                 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1244                         rdata, ofs + 0x08);
1245                 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1246                         rdata, ofs + 0x10);
1247
1248                 if (nlen > data_len - (ofs + 24)) {
1249                         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                 tmp_buf = talloc_array(streams, uint8_t, nlen+2);
1258                 if (tmp_buf == NULL) {
1259                         goto fail;
1260                 }
1261
1262                 memcpy(tmp_buf, rdata+ofs+24, nlen);
1263                 tmp_buf[nlen] = 0;
1264                 tmp_buf[nlen+1] = 0;
1265
1266                 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1267                                            nlen+2, &vstr, &size))
1268                 {
1269                         TALLOC_FREE(tmp_buf);
1270                         goto fail;
1271                 }
1272
1273                 TALLOC_FREE(tmp_buf);
1274                 streams[num_streams].name = (char *)vstr;
1275                 num_streams++;
1276
1277                 len = IVAL(rdata, ofs);
1278                 if (len > data_len - ofs) {
1279                         goto fail;
1280                 }
1281                 if (len == 0) break;
1282                 ofs += len;
1283         }
1284
1285         *pnum_streams = num_streams;
1286         *pstreams = streams;
1287         return true;
1288
1289  fail:
1290         TALLOC_FREE(streams);
1291         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 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         struct tevent_req *req = NULL, *subreq = NULL;
1319         struct cli_qfileinfo_basic_state *state = NULL;
1320
1321         req = tevent_req_create(
1322                 mem_ctx, &state, struct cli_qfileinfo_basic_state);
1323         if (req == NULL) {
1324                 return NULL;
1325         }
1326
1327         if ((smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN2) ||
1328             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                 subreq = cli_getattrE_send(state, ev, cli, fnum);
1344                 if (tevent_req_nomem(subreq, req)) {
1345                         return tevent_req_post(req, ev);
1346                 }
1347                 tevent_req_set_callback(
1348                         subreq, cli_qfileinfo_basic_doneE, req);
1349                 return req;
1350         }
1351
1352         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1353                 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                 if (tevent_req_nomem(subreq, req)) {
1365                         return tevent_req_post(req, ev);
1366                 }
1367                 tevent_req_set_callback(
1368                         subreq, cli_qfileinfo_basic_done2, req);
1369                 return req;
1370         }
1371
1372         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         if (tevent_req_nomem(subreq, req)) {
1381                 return tevent_req_post(req, ev);
1382         }
1383         tevent_req_set_callback(subreq, cli_qfileinfo_basic_done, req);
1384         return req;
1385 }
1386
1387 static void cli_qfileinfo_basic_done(struct tevent_req *subreq)
1388 {
1389         struct tevent_req *req = tevent_req_callback_data(
1390                 subreq, struct tevent_req);
1391         struct cli_qfileinfo_basic_state *state = tevent_req_data(
1392                 req, struct cli_qfileinfo_basic_state);
1393         uint8_t *rdata;
1394         uint32_t num_rdata;
1395         NTSTATUS status;
1396
1397         status = cli_qfileinfo_recv(
1398                 subreq, state, NULL, &rdata, &num_rdata);
1399         TALLOC_FREE(subreq);
1400         if (tevent_req_nterror(req, status)) {
1401                 return;
1402         }
1403
1404         state->create_time = interpret_long_date(BVAL(rdata, 0));
1405         state->access_time = interpret_long_date(BVAL(rdata, 8));
1406         state->write_time = interpret_long_date(BVAL(rdata, 16));
1407         state->change_time = interpret_long_date(BVAL(rdata, 24));
1408         state->attr = PULL_LE_U32(rdata, 32);
1409         state->size = PULL_LE_U64(rdata,48);
1410         state->ino = PULL_LE_U32(rdata, 64);
1411         TALLOC_FREE(rdata);
1412
1413         tevent_req_done(req);
1414 }
1415
1416 static void cli_qfileinfo_basic_doneE(struct tevent_req *subreq)
1417 {
1418         struct tevent_req *req = tevent_req_callback_data(
1419                 subreq, struct tevent_req);
1420         struct cli_qfileinfo_basic_state *state = tevent_req_data(
1421                 req, struct cli_qfileinfo_basic_state);
1422         NTSTATUS status;
1423
1424         status = cli_getattrE_recv(
1425                 subreq,
1426                 &state->attr,
1427                 &state->size,
1428                 &state->change_time.tv_sec,
1429                 &state->access_time.tv_sec,
1430                 &state->write_time.tv_sec);
1431         TALLOC_FREE(subreq);
1432         if (tevent_req_nterror(req, status)) {
1433                 return;
1434         }
1435         tevent_req_done(req);
1436 }
1437
1438 static void cli_qfileinfo_basic_done2(struct tevent_req *subreq)
1439 {
1440         struct tevent_req *req = tevent_req_callback_data(
1441                 subreq, struct tevent_req);
1442         struct cli_qfileinfo_basic_state *state = tevent_req_data(
1443                 req, struct cli_qfileinfo_basic_state);
1444         DATA_BLOB outbuf = {0};
1445         NTSTATUS status;
1446
1447         status = cli_smb2_query_info_fnum_recv(subreq, state, &outbuf);
1448         TALLOC_FREE(subreq);
1449         if (tevent_req_nterror(req, status)) {
1450                 return;
1451         }
1452
1453         /* Parse the reply. */
1454         if (outbuf.length < 0x60) {
1455                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1456                 return;
1457         }
1458
1459         state->create_time = interpret_long_date(BVAL(outbuf.data, 0x0));
1460         state->access_time = interpret_long_date(BVAL(outbuf.data, 0x8));
1461         state->write_time = interpret_long_date(BVAL(outbuf.data, 0x10));
1462         state->change_time = interpret_long_date(BVAL(outbuf.data, 0x18));
1463         state->attr = IVAL(outbuf.data, 0x20);
1464         state->size = BVAL(outbuf.data, 0x30);
1465         state->ino = BVAL(outbuf.data, 0x40);
1466
1467         data_blob_free(&outbuf);
1468
1469         tevent_req_done(req);
1470 }
1471
1472 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         struct cli_qfileinfo_basic_state *state = tevent_req_data(
1483                 req, struct cli_qfileinfo_basic_state);
1484         NTSTATUS status;
1485
1486         if (tevent_req_is_nterror(req, &status)) {
1487                 return status;
1488         }
1489
1490         if (create_time != NULL) {
1491                 *create_time = state->create_time;
1492         }
1493         if (access_time != NULL) {
1494                 *access_time = state->access_time;
1495         }
1496         if (write_time != NULL) {
1497                 *write_time = state->write_time;
1498         }
1499         if (change_time != NULL) {
1500                 *change_time = state->change_time;
1501         }
1502         if (attr != NULL) {
1503                 *attr = state->attr;
1504         }
1505         if (size != NULL) {
1506                 *size = state->size;
1507         }
1508         if (ino) {
1509                 *ino = state->ino;
1510         }
1511
1512         return NT_STATUS_OK;
1513 }
1514 /****************************************************************************
1515  Send a qfileinfo call.
1516 ****************************************************************************/
1517
1518 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         TALLOC_CTX *frame = NULL;
1530         struct tevent_context *ev = NULL;
1531         struct tevent_req *req = NULL;
1532         NTSTATUS status = NT_STATUS_NO_MEMORY;
1533
1534         frame = talloc_stackframe();
1535
1536         if (smbXcli_conn_has_async_calls(cli->conn)) {
1537                 /*
1538                  * Can't use sync call while an async call is in flight
1539                  */
1540                 status = NT_STATUS_INVALID_PARAMETER;
1541                 goto fail;
1542         }
1543         ev = samba_tevent_context_init(frame);
1544         if (ev == NULL) {
1545                 goto fail;
1546         }
1547         req = cli_qfileinfo_basic_send(frame, ev, cli, fnum);
1548         if (req == NULL) {
1549                 goto fail;
1550         }
1551         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1552                 goto fail;
1553         }
1554
1555         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         cli->raw_status = status;
1567 fail:
1568         TALLOC_FREE(frame);
1569         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 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         struct tevent_req *req = NULL, *subreq = NULL;
1589         struct cli_qpathinfo_basic_state *state = NULL;
1590
1591         req = tevent_req_create(mem_ctx, &state,
1592                                 struct cli_qpathinfo_basic_state);
1593         if (req == NULL) {
1594                 return NULL;
1595         }
1596         subreq = cli_qpathinfo_send(state, ev, cli, fname,
1597                                     SMB_QUERY_FILE_BASIC_INFO,
1598                                     36, CLI_BUFFER_SIZE);
1599         if (tevent_req_nomem(subreq, req)) {
1600                 return tevent_req_post(req, ev);
1601         }
1602         tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1603         return req;
1604 }
1605
1606 static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1607 {
1608         struct tevent_req *req = tevent_req_callback_data(
1609                 subreq, struct tevent_req);
1610         struct cli_qpathinfo_basic_state *state = tevent_req_data(
1611                 req, struct cli_qpathinfo_basic_state);
1612         NTSTATUS status;
1613
1614         status = cli_qpathinfo_recv(subreq, state, &state->data,
1615                                     &state->num_data);
1616         TALLOC_FREE(subreq);
1617         if (tevent_req_nterror(req, status)) {
1618                 return;
1619         }
1620         tevent_req_done(req);
1621 }
1622
1623 NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1624                                   SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1625 {
1626         struct cli_qpathinfo_basic_state *state = tevent_req_data(
1627                 req, struct cli_qpathinfo_basic_state);
1628         NTSTATUS status;
1629
1630         if (tevent_req_is_nterror(req, &status)) {
1631                 return status;
1632         }
1633
1634         sbuf->st_ex_btime = interpret_long_date(BVAL(state->data, 0));
1635         sbuf->st_ex_atime = interpret_long_date(BVAL(state->data, 8));
1636         sbuf->st_ex_mtime = interpret_long_date(BVAL(state->data, 16));
1637         sbuf->st_ex_ctime = interpret_long_date(BVAL(state->data, 24));
1638         *attributes = IVAL(state->data, 32);
1639         return NT_STATUS_OK;
1640 }
1641
1642 NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1643                              SMB_STRUCT_STAT *sbuf, uint32_t *attributes)
1644 {
1645         TALLOC_CTX *frame = NULL;
1646         struct tevent_context *ev;
1647         struct tevent_req *req;
1648         NTSTATUS status = NT_STATUS_NO_MEMORY;
1649
1650         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1651                 return cli_smb2_qpathinfo_basic(cli,
1652                                                 name,
1653                                                 sbuf,
1654                                                 attributes);
1655         }
1656
1657         frame = talloc_stackframe();
1658
1659         if (smbXcli_conn_has_async_calls(cli->conn)) {
1660                 /*
1661                  * Can't use sync call while an async call is in flight
1662                  */
1663                 status = NT_STATUS_INVALID_PARAMETER;
1664                 goto fail;
1665         }
1666         ev = samba_tevent_context_init(frame);
1667         if (ev == NULL) {
1668                 goto fail;
1669         }
1670         req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1671         if (req == NULL) {
1672                 goto fail;
1673         }
1674         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1675                 goto fail;
1676         }
1677         status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1678  fail:
1679         TALLOC_FREE(frame);
1680         return status;
1681 }
1682
1683 /****************************************************************************
1684  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1685 ****************************************************************************/
1686
1687 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1688 {
1689         uint8_t *rdata;
1690         uint32_t num_rdata;
1691         unsigned int len;
1692         char *converted = NULL;
1693         size_t converted_size = 0;
1694         NTSTATUS status;
1695
1696         status = cli_qpathinfo(talloc_tos(), cli, fname,
1697                                SMB_QUERY_FILE_ALT_NAME_INFO,
1698                                4, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1699         if (!NT_STATUS_IS_OK(status)) {
1700                 return status;
1701         }
1702
1703         len = IVAL(rdata, 0);
1704
1705         if (len > num_rdata - 4) {
1706                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1707         }
1708
1709         /* The returned data is a pushed string, not raw data. */
1710         if (!convert_string_talloc(talloc_tos(),
1711                                    smbXcli_conn_use_unicode(cli->conn) ? CH_UTF16LE : CH_DOS,
1712                                    CH_UNIX,
1713                                    rdata + 4,
1714                                    len,
1715                                    &converted,
1716                                    &converted_size)) {
1717                 return NT_STATUS_NO_MEMORY;
1718         }
1719         fstrcpy(alt_name, converted);
1720
1721         TALLOC_FREE(converted);
1722         TALLOC_FREE(rdata);
1723
1724         return NT_STATUS_OK;
1725 }
1726
1727 /****************************************************************************
1728  Send a qpathinfo SMB_QUERY_FILE_STANDARD_INFO call.
1729 ****************************************************************************/
1730
1731 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         uint8_t *rdata;
1737         uint32_t num_rdata;
1738         NTSTATUS status;
1739
1740         if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1741                 return NT_STATUS_NOT_IMPLEMENTED;
1742         }
1743
1744         status = cli_qpathinfo(talloc_tos(), cli, fname,
1745                                SMB_QUERY_FILE_STANDARD_INFO,
1746                                24, CLI_BUFFER_SIZE, &rdata, &num_rdata);
1747         if (!NT_STATUS_IS_OK(status)) {
1748                 return status;
1749         }
1750
1751         if (allocated) {
1752                 *allocated = BVAL(rdata, 0);
1753         }
1754
1755         if (size) {
1756                 *size = BVAL(rdata, 8);
1757         }
1758
1759         if (nlinks) {
1760                 *nlinks = IVAL(rdata, 16);
1761         }
1762
1763         if (is_del_pending) {
1764                 *is_del_pending = CVAL(rdata, 20);
1765         }
1766
1767         if (is_dir) {
1768                 *is_dir = CVAL(rdata, 20);
1769         }
1770
1771         TALLOC_FREE(rdata);
1772
1773         return NT_STATUS_OK;
1774 }
1775
1776
1777 /* like cli_qpathinfo2 but do not use SMB_QUERY_FILE_ALL_INFO with smb1 */
1778 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         NTSTATUS status = NT_STATUS_OK;
1787         SMB_STRUCT_STAT st = { 0 };
1788         uint32_t attr = 0;
1789         uint64_t pos;
1790
1791         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                 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         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                 status = cli_qpathinfo_basic(cli, fname, &st, &attr);
1818                 if (!NT_STATUS_IS_OK(status)) {
1819                         return status;
1820                 }
1821         }
1822
1823         if (size) {
1824                 status = cli_qpathinfo_standard(cli, fname,
1825                                                 NULL, &pos, NULL, NULL, NULL);
1826                 if (!NT_STATUS_IS_OK(status)) {
1827                         return status;
1828                 }
1829
1830                 *size = pos;
1831         }
1832
1833         if (create_time) {
1834                 *create_time = st.st_ex_btime;
1835         }
1836         if (access_time) {
1837                 *access_time = st.st_ex_atime;
1838         }
1839         if (write_time) {
1840                 *write_time = st.st_ex_mtime;
1841         }
1842         if (change_time) {
1843                 *change_time = st.st_ex_ctime;
1844         }
1845         if (pattr) {
1846                 *pattr = attr;
1847         }
1848         if (ino) {
1849                 *ino = 0;
1850         }
1851
1852         return NT_STATUS_OK;
1853 }