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