charcnv: removed the allow_badcharcnv and allow_bad_conv options to convert_string*()
[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/crypto/arcfour.h"
26 #include "async_smb.h"
27 #include "libsmb/clirap.h"
28
29 #define PIPE_LANMAN   "\\PIPE\\LANMAN"
30
31 /****************************************************************************
32  Call a remote api
33 ****************************************************************************/
34
35 bool cli_api(struct cli_state *cli,
36              char *param, int prcnt, int mprcnt,
37              char *data, int drcnt, int mdrcnt,
38              char **rparam, unsigned int *rprcnt,
39              char **rdata, unsigned int *rdrcnt)
40 {
41         NTSTATUS status;
42
43         uint8_t *my_rparam, *my_rdata;
44         uint32_t num_my_rparam, num_my_rdata;
45
46         status = cli_trans(talloc_tos(), cli, SMBtrans,
47                            PIPE_LANMAN, 0, /* name, fid */
48                            0, 0,           /* function, flags */
49                            NULL, 0, 0,     /* setup */
50                            (uint8_t *)param, prcnt, mprcnt, /* Params, length, max */
51                            (uint8_t *)data, drcnt, mdrcnt,  /* Data, length, max */
52                            NULL,                 /* recv_flags2 */
53                            NULL, 0, NULL,        /* rsetup */
54                            &my_rparam, 0, &num_my_rparam,
55                            &my_rdata, 0, &num_my_rdata);
56         if (!NT_STATUS_IS_OK(status)) {
57                 return false;
58         }
59
60         /*
61          * I know this memcpy massively hurts, but there are just tons
62          * of callers of cli_api that eventually need changing to
63          * talloc
64          */
65
66         *rparam = (char *)memdup(my_rparam, num_my_rparam);
67         if (*rparam == NULL) {
68                 goto fail;
69         }
70         *rprcnt = num_my_rparam;
71         TALLOC_FREE(my_rparam);
72
73         *rdata = (char *)memdup(my_rdata, num_my_rdata);
74         if (*rdata == NULL) {
75                 goto fail;
76         }
77         *rdrcnt = num_my_rdata;
78         TALLOC_FREE(my_rdata);
79
80         return true;
81 fail:
82         TALLOC_FREE(my_rdata);
83         TALLOC_FREE(my_rparam);
84         *rparam = NULL;
85         *rprcnt = 0;
86         *rdata = NULL;
87         *rdrcnt = 0;
88         return false;
89 }
90
91 /****************************************************************************
92  Perform a NetWkstaUserLogon.
93 ****************************************************************************/
94
95 bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
96 {
97         char *rparam = NULL;
98         char *rdata = NULL;
99         char *p;
100         unsigned int rdrcnt,rprcnt;
101         char param[1024];
102
103         memset(param, 0, sizeof(param));
104
105         /* send a SMBtrans command with api NetWkstaUserLogon */
106         p = param;
107         SSVAL(p,0,132); /* api number */
108         p += 2;
109         strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
110         p = skip_string(param,sizeof(param),p);
111         strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
112         p = skip_string(param,sizeof(param),p);
113         SSVAL(p,0,1);
114         p += 2;
115         strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
116         strupper_m(p);
117         p += 21;
118         p++;
119         p += 15;
120         p++;
121         strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
122         strupper_m(p);
123         p += 16;
124         SSVAL(p, 0, CLI_BUFFER_SIZE);
125         p += 2;
126         SSVAL(p, 0, CLI_BUFFER_SIZE);
127         p += 2;
128
129         if (cli_api(cli,
130                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
131                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
132                     &rparam, &rprcnt,               /* return params, return size */
133                     &rdata, &rdrcnt                 /* return data, return size */
134                    )) {
135                 cli->rap_error = rparam? SVAL(rparam,0) : -1;
136                 p = rdata;
137
138                 if (cli->rap_error == 0) {
139                         DEBUG(4,("NetWkstaUserLogon success\n"));
140                         cli->privileges = SVAL(p, 24);
141                         /* The cli->eff_name field used to be set here
142                            but it wasn't used anywhere else. */
143                 } else {
144                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
145                 }
146         }
147
148         SAFE_FREE(rparam);
149         SAFE_FREE(rdata);
150         return (cli->rap_error == 0);
151 }
152
153 /****************************************************************************
154  Call a NetShareEnum - try and browse available connections on a host.
155 ****************************************************************************/
156
157 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
158 {
159         char *rparam = NULL;
160         char *rdata = NULL;
161         char *p;
162         unsigned int rdrcnt,rprcnt;
163         char param[1024];
164         int count = -1;
165
166         /* now send a SMBtrans command with api RNetShareEnum */
167         p = param;
168         SSVAL(p,0,0); /* api number */
169         p += 2;
170         strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
171         p = skip_string(param,sizeof(param),p);
172         strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
173         p = skip_string(param,sizeof(param),p);
174         SSVAL(p,0,1);
175         /*
176          * Win2k needs a *smaller* buffer than 0xFFFF here -
177          * it returns "out of server memory" with 0xFFFF !!! JRA.
178          */
179         SSVAL(p,2,0xFFE0);
180         p += 4;
181
182         if (cli_api(cli,
183                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
184                     NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
185                     &rparam, &rprcnt,                /* return params, length */
186                     &rdata, &rdrcnt))                /* return data, length */
187                 {
188                         int res = rparam? SVAL(rparam,0) : -1;
189
190                         if (res == 0 || res == ERRmoredata) {
191                                 int converter=SVAL(rparam,2);
192                                 int i;
193                                 char *rdata_end = rdata + rdrcnt;
194
195                                 count=SVAL(rparam,4);
196                                 p = rdata;
197
198                                 for (i=0;i<count;i++,p+=20) {
199                                         char *sname;
200                                         int type;
201                                         int comment_offset;
202                                         const char *cmnt;
203                                         const char *p1;
204                                         char *s1, *s2;
205                                         size_t len;
206                                         TALLOC_CTX *frame = talloc_stackframe();
207
208                                         if (p + 20 > rdata_end) {
209                                                 TALLOC_FREE(frame);
210                                                 break;
211                                         }
212
213                                         sname = p;
214                                         type = SVAL(p,14);
215                                         comment_offset = (IVAL(p,16) & 0xFFFF) - converter;
216                                         if (comment_offset < 0 ||
217                                                         comment_offset > (int)rdrcnt) {
218                                                 TALLOC_FREE(frame);
219                                                 break;
220                                         }
221                                         cmnt = comment_offset?(rdata+comment_offset):"";
222
223                                         /* Work out the comment length. */
224                                         for (p1 = cmnt, len = 0; *p1 &&
225                                                         p1 < rdata_end; len++)
226                                                 p1++;
227                                         if (!*p1) {
228                                                 len++;
229                                         }
230                                         pull_string_talloc(frame,rdata,0,
231                                                 &s1,sname,14,STR_ASCII);
232                                         pull_string_talloc(frame,rdata,0,
233                                                 &s2,cmnt,len,STR_ASCII);
234                                         if (!s1 || !s2) {
235                                                 TALLOC_FREE(frame);
236                                                 continue;
237                                         }
238
239                                         fn(s1, type, s2, state);
240
241                                         TALLOC_FREE(frame);
242                                 }
243                         } else {
244                                 DEBUG(4,("NetShareEnum res=%d\n", res));
245                         }
246                 } else {
247                         DEBUG(4,("NetShareEnum failed\n"));
248                 }
249
250         SAFE_FREE(rparam);
251         SAFE_FREE(rdata);
252
253         return count;
254 }
255
256 /****************************************************************************
257  Call a NetServerEnum for the specified workgroup and servertype mask.  This
258  function then calls the specified callback function for each name returned.
259
260  The callback function takes 4 arguments: the machine name, the server type,
261  the comment and a state pointer.
262 ****************************************************************************/
263
264 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
265                        void (*fn)(const char *, uint32, const char *, void *),
266                        void *state)
267 {
268         char *rparam = NULL;
269         char *rdata = NULL;
270         char *rdata_end = NULL;
271         unsigned int rdrcnt,rprcnt;
272         char *p;
273         char param[1024];
274         int uLevel = 1;
275         size_t len;
276         uint32 func = RAP_NetServerEnum2;
277         char *last_entry = NULL;
278         int total_cnt = 0;
279         int return_cnt = 0;
280         int res;
281
282         errno = 0; /* reset */
283
284         /*
285          * This may take more than one transaction, so we should loop until
286          * we no longer get a more data to process or we have all of the
287          * items.
288          */
289         do {
290                 /* send a SMBtrans command with api NetServerEnum */
291                 p = param;
292                 SIVAL(p,0,func); /* api number */
293                 p += 2;
294
295                 if (func == RAP_NetServerEnum3) {
296                         strlcpy(p,"WrLehDzz", sizeof(param)-PTR_DIFF(p,param));
297                 } else {
298                         strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
299                 }
300
301                 p = skip_string(param, sizeof(param), p);
302                 strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
303
304                 p = skip_string(param, sizeof(param), p);
305                 SSVAL(p,0,uLevel);
306                 SSVAL(p,2,CLI_BUFFER_SIZE);
307                 p += 4;
308                 SIVAL(p,0,stype);
309                 p += 4;
310
311                 /* If we have more data, tell the server where
312                  * to continue from.
313                  */
314                 len = push_ascii(p,
315                                 workgroup,
316                                 sizeof(param) - PTR_DIFF(p,param) - 1,
317                                 STR_TERMINATE|STR_UPPER);
318
319                 if (len == (size_t)-1) {
320                         SAFE_FREE(last_entry);
321                         return false;
322                 }
323                 p += len;
324
325                 if (func == RAP_NetServerEnum3) {
326                         len = push_ascii(p,
327                                         last_entry ? last_entry : "",
328                                         sizeof(param) - PTR_DIFF(p,param) - 1,
329                                         STR_TERMINATE);
330
331                         if (len == (size_t)-1) {
332                                 SAFE_FREE(last_entry);
333                                 return false;
334                         }
335                         p += len;
336                 }
337
338                 /* Next time through we need to use the continue api */
339                 func = RAP_NetServerEnum3;
340
341                 if (!cli_api(cli,
342                         param, PTR_DIFF(p,param), 8, /* params, length, max */
343                         NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
344                             &rparam, &rprcnt, /* return params, return size */
345                             &rdata, &rdrcnt)) { /* return data, return size */
346
347                         /* break out of the loop on error */
348                         res = -1;
349                         break;
350                 }
351
352                 rdata_end = rdata + rdrcnt;
353                 res = rparam ? SVAL(rparam,0) : -1;
354
355                 if (res == 0 || res == ERRmoredata ||
356                     (res != -1 && cli_errno(cli) == 0)) {
357                         char *sname = NULL;
358                         int i, count;
359                         int converter=SVAL(rparam,2);
360
361                         /* Get the number of items returned in this buffer */
362                         count = SVAL(rparam, 4);
363
364                         /* The next field contains the number of items left,
365                          * including those returned in this buffer. So the
366                          * first time through this should contain all of the
367                          * entries.
368                          */
369                         if (total_cnt == 0) {
370                                 total_cnt = SVAL(rparam, 6);
371                         }
372
373                         /* Keep track of how many we have read */
374                         return_cnt += count;
375                         p = rdata;
376
377                         /* The last name in the previous NetServerEnum reply is
378                          * sent back to server in the NetServerEnum3 request
379                          * (last_entry). The next reply should repeat this entry
380                          * as the first element. We have no proof that this is
381                          * always true, but from traces that seems to be the
382                          * behavior from Window Servers. So first lets do a lot
383                          * of checking, just being paranoid. If the string
384                          * matches then we already saw this entry so skip it.
385                          *
386                          * NOTE: sv1_name field must be null terminated and has
387                          * a max size of 16 (NetBIOS Name).
388                          */
389                         if (last_entry && count && p &&
390                                 (strncmp(last_entry, p, 16) == 0)) {
391                             count -= 1; /* Skip this entry */
392                             return_cnt = -1; /* Not part of total, so don't count. */
393                             p = rdata + 26; /* Skip the whole record */
394                         }
395
396                         for (i = 0; i < count; i++, p += 26) {
397                                 int comment_offset;
398                                 const char *cmnt;
399                                 const char *p1;
400                                 char *s1, *s2;
401                                 TALLOC_CTX *frame = talloc_stackframe();
402                                 uint32_t entry_stype;
403
404                                 if (p + 26 > rdata_end) {
405                                         TALLOC_FREE(frame);
406                                         break;
407                                 }
408
409                                 sname = p;
410                                 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
411                                 cmnt = comment_offset?(rdata+comment_offset):"";
412
413                                 if (comment_offset < 0 || comment_offset >= (int)rdrcnt) {
414                                         TALLOC_FREE(frame);
415                                         continue;
416                                 }
417
418                                 /* Work out the comment length. */
419                                 for (p1 = cmnt, len = 0; *p1 &&
420                                                 p1 < rdata_end; len++)
421                                         p1++;
422                                 if (!*p1) {
423                                         len++;
424                                 }
425
426                                 entry_stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
427
428                                 pull_string_talloc(frame,rdata,0,
429                                         &s1,sname,16,STR_ASCII);
430                                 pull_string_talloc(frame,rdata,0,
431                                         &s2,cmnt,len,STR_ASCII);
432
433                                 if (!s1 || !s2) {
434                                         TALLOC_FREE(frame);
435                                         continue;
436                                 }
437
438                                 fn(s1, entry_stype, s2, state);
439                                 TALLOC_FREE(frame);
440                         }
441
442                         /* We are done with the old last entry, so now we can free it */
443                         if (last_entry) {
444                                 SAFE_FREE(last_entry); /* This will set it to null */
445                         }
446
447                         /* We always make a copy of  the last entry if we have one */
448                         if (sname) {
449                                 last_entry = smb_xstrdup(sname);
450                         }
451
452                         /* If we have more data, but no last entry then error out */
453                         if (!last_entry && (res == ERRmoredata)) {
454                                 errno = EINVAL;
455                                 res = 0;
456                         }
457
458                 }
459
460                 SAFE_FREE(rparam);
461                 SAFE_FREE(rdata);
462         } while ((res == ERRmoredata) && (total_cnt > return_cnt));
463
464         SAFE_FREE(rparam);
465         SAFE_FREE(rdata);
466         SAFE_FREE(last_entry);
467
468         if (res == -1) {
469                 errno = cli_errno(cli);
470         } else {
471                 if (!return_cnt) {
472                         /* this is a very special case, when the domain master for the
473                            work group isn't part of the work group itself, there is something
474                            wild going on */
475                         errno = ENOENT;
476                 }
477             }
478
479         return(return_cnt > 0);
480 }
481
482 /****************************************************************************
483  Send a SamOEMChangePassword command.
484 ****************************************************************************/
485
486 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
487                              const char *old_password)
488 {
489         char param[1024];
490         unsigned char data[532];
491         char *p = param;
492         unsigned char old_pw_hash[16];
493         unsigned char new_pw_hash[16];
494         unsigned int data_len;
495         unsigned int param_len = 0;
496         char *rparam = NULL;
497         char *rdata = NULL;
498         unsigned int rprcnt, rdrcnt;
499
500         if (strlen(user) >= sizeof(fstring)-1) {
501                 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
502                 return False;
503         }
504
505         SSVAL(p,0,214); /* SamOEMChangePassword command. */
506         p += 2;
507         strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
508         p = skip_string(param,sizeof(param),p);
509         strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
510         p = skip_string(param,sizeof(param),p);
511         strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
512         p = skip_string(param,sizeof(param),p);
513         SSVAL(p,0,532);
514         p += 2;
515
516         param_len = PTR_DIFF(p,param);
517
518         /*
519          * Get the Lanman hash of the old password, we
520          * use this as the key to make_oem_passwd_hash().
521          */
522         E_deshash(old_password, old_pw_hash);
523
524         encode_pw_buffer(data, new_password, STR_ASCII);
525
526 #ifdef DEBUG_PASSWORD
527         DEBUG(100,("make_oem_passwd_hash\n"));
528         dump_data(100, data, 516);
529 #endif
530         arcfour_crypt( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
531
532         /*
533          * Now place the old password hash in the data.
534          */
535         E_deshash(new_password, new_pw_hash);
536
537         E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
538
539         data_len = 532;
540
541         if (!cli_api(cli,
542                      param, param_len, 4,               /* param, length, max */
543                      (char *)data, data_len, 0,         /* data, length, max */
544                      &rparam, &rprcnt,
545                      &rdata, &rdrcnt)) {
546                 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
547                         user ));
548                 return False;
549         }
550
551         if (rparam) {
552                 cli->rap_error = SVAL(rparam,0);
553         }
554
555         SAFE_FREE(rparam);
556         SAFE_FREE(rdata);
557
558         return (cli->rap_error == 0);
559 }
560
561 /****************************************************************************
562  Send a qpathinfo call.
563 ****************************************************************************/
564
565 struct cli_qpathinfo1_state {
566         struct cli_state *cli;
567         uint32_t num_data;
568         uint8_t *data;
569 };
570
571 static void cli_qpathinfo1_done(struct tevent_req *subreq);
572
573 struct tevent_req *cli_qpathinfo1_send(TALLOC_CTX *mem_ctx,
574                                        struct event_context *ev,
575                                        struct cli_state *cli,
576                                        const char *fname)
577 {
578         struct tevent_req *req = NULL, *subreq = NULL;
579         struct cli_qpathinfo1_state *state = NULL;
580
581         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo1_state);
582         if (req == NULL) {
583                 return NULL;
584         }
585         state->cli = cli;
586         subreq = cli_qpathinfo_send(state, ev, cli, fname, SMB_INFO_STANDARD,
587                                     22, cli->max_xmit);
588         if (tevent_req_nomem(subreq, req)) {
589                 return tevent_req_post(req, ev);
590         }
591         tevent_req_set_callback(subreq, cli_qpathinfo1_done, req);
592         return req;
593 }
594
595 static void cli_qpathinfo1_done(struct tevent_req *subreq)
596 {
597         struct tevent_req *req = tevent_req_callback_data(
598                 subreq, struct tevent_req);
599         struct cli_qpathinfo1_state *state = tevent_req_data(
600                 req, struct cli_qpathinfo1_state);
601         NTSTATUS status;
602
603         status = cli_qpathinfo_recv(subreq, state, &state->data,
604                                     &state->num_data);
605         TALLOC_FREE(subreq);
606         if (!NT_STATUS_IS_OK(status)) {
607                 tevent_req_nterror(req, status);
608                 return;
609         }
610         tevent_req_done(req);
611 }
612
613 NTSTATUS cli_qpathinfo1_recv(struct tevent_req *req,
614                              time_t *change_time,
615                              time_t *access_time,
616                              time_t *write_time,
617                              SMB_OFF_T *size,
618                              uint16 *mode)
619 {
620         struct cli_qpathinfo1_state *state = tevent_req_data(
621                 req, struct cli_qpathinfo1_state);
622         NTSTATUS status;
623
624         time_t (*date_fn)(const void *buf, int serverzone);
625
626         if (tevent_req_is_nterror(req, &status)) {
627                 return status;
628         }
629
630         if (state->cli->win95) {
631                 date_fn = make_unix_date;
632         } else {
633                 date_fn = make_unix_date2;
634         }
635
636         if (change_time) {
637                 *change_time = date_fn(state->data+0, state->cli->serverzone);
638         }
639         if (access_time) {
640                 *access_time = date_fn(state->data+4, state->cli->serverzone);
641         }
642         if (write_time) {
643                 *write_time = date_fn(state->data+8, state->cli->serverzone);
644         }
645         if (size) {
646                 *size = IVAL(state->data, 12);
647         }
648         if (mode) {
649                 *mode = SVAL(state->data, l1_attrFile);
650         }
651         return NT_STATUS_OK;
652 }
653
654 NTSTATUS cli_qpathinfo1(struct cli_state *cli,
655                         const char *fname,
656                         time_t *change_time,
657                         time_t *access_time,
658                         time_t *write_time,
659                         SMB_OFF_T *size,
660                         uint16 *mode)
661 {
662         TALLOC_CTX *frame = talloc_stackframe();
663         struct event_context *ev;
664         struct tevent_req *req;
665         NTSTATUS status = NT_STATUS_NO_MEMORY;
666
667         if (cli_has_async_calls(cli)) {
668                 /*
669                  * Can't use sync call while an async call is in flight
670                  */
671                 status = NT_STATUS_INVALID_PARAMETER;
672                 goto fail;
673         }
674         ev = event_context_init(frame);
675         if (ev == NULL) {
676                 goto fail;
677         }
678         req = cli_qpathinfo1_send(frame, ev, cli, fname);
679         if (req == NULL) {
680                 goto fail;
681         }
682         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
683                 goto fail;
684         }
685         status = cli_qpathinfo1_recv(req, change_time, access_time,
686                                      write_time, size, mode);
687  fail:
688         TALLOC_FREE(frame);
689         if (!NT_STATUS_IS_OK(status)) {
690                 cli_set_error(cli, status);
691         }
692         return status;
693 }
694
695 /****************************************************************************
696  Send a setpathinfo call.
697 ****************************************************************************/
698
699 NTSTATUS cli_setpathinfo_basic(struct cli_state *cli, const char *fname,
700                                time_t create_time,
701                                time_t access_time,
702                                time_t write_time,
703                                time_t change_time,
704                                uint16 mode)
705 {
706         unsigned int data_len = 0;
707         char data[40];
708         char *p;
709
710         p = data;
711
712         /*
713          * Add the create, last access, modification, and status change times
714          */
715         put_long_date(p, create_time);
716         p += 8;
717
718         put_long_date(p, access_time);
719         p += 8;
720
721         put_long_date(p, write_time);
722         p += 8;
723
724         put_long_date(p, change_time);
725         p += 8;
726
727         /* Add attributes */
728         SIVAL(p, 0, mode);
729         p += 4;
730
731         /* Add padding */
732         SIVAL(p, 0, 0);
733         p += 4;
734
735         data_len = PTR_DIFF(p, data);
736
737         return cli_setpathinfo(cli, SMB_FILE_BASIC_INFORMATION, fname,
738                                (uint8_t *)data, data_len);
739 }
740
741 /****************************************************************************
742  Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
743 ****************************************************************************/
744
745 struct cli_qpathinfo2_state {
746         uint32_t num_data;
747         uint8_t *data;
748 };
749
750 static void cli_qpathinfo2_done(struct tevent_req *subreq);
751
752 struct tevent_req *cli_qpathinfo2_send(TALLOC_CTX *mem_ctx,
753                                        struct event_context *ev,
754                                        struct cli_state *cli,
755                                        const char *fname)
756 {
757         struct tevent_req *req = NULL, *subreq = NULL;
758         struct cli_qpathinfo2_state *state = NULL;
759
760         req = tevent_req_create(mem_ctx, &state, struct cli_qpathinfo2_state);
761         if (req == NULL) {
762                 return NULL;
763         }
764         subreq = cli_qpathinfo_send(state, ev, cli, fname,
765                                     SMB_QUERY_FILE_ALL_INFO,
766                                     68, cli->max_xmit);
767         if (tevent_req_nomem(subreq, req)) {
768                 return tevent_req_post(req, ev);
769         }
770         tevent_req_set_callback(subreq, cli_qpathinfo2_done, req);
771         return req;
772 }
773
774 static void cli_qpathinfo2_done(struct tevent_req *subreq)
775 {
776         struct tevent_req *req = tevent_req_callback_data(
777                 subreq, struct tevent_req);
778         struct cli_qpathinfo2_state *state = tevent_req_data(
779                 req, struct cli_qpathinfo2_state);
780         NTSTATUS status;
781
782         status = cli_qpathinfo_recv(subreq, state, &state->data,
783                                     &state->num_data);
784         TALLOC_FREE(subreq);
785         if (!NT_STATUS_IS_OK(status)) {
786                 tevent_req_nterror(req, status);
787                 return;
788         }
789         tevent_req_done(req);
790 }
791
792 NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req,
793                              struct timespec *create_time,
794                              struct timespec *access_time,
795                              struct timespec *write_time,
796                              struct timespec *change_time,
797                              SMB_OFF_T *size, uint16 *mode,
798                              SMB_INO_T *ino)
799 {
800         struct cli_qpathinfo2_state *state = tevent_req_data(
801                 req, struct cli_qpathinfo2_state);
802         NTSTATUS status;
803
804         if (tevent_req_is_nterror(req, &status)) {
805                 return status;
806         }
807
808         if (create_time) {
809                 *create_time = interpret_long_date((char *)state->data+0);
810         }
811         if (access_time) {
812                 *access_time = interpret_long_date((char *)state->data+8);
813         }
814         if (write_time) {
815                 *write_time = interpret_long_date((char *)state->data+16);
816         }
817         if (change_time) {
818                 *change_time = interpret_long_date((char *)state->data+24);
819         }
820         if (mode) {
821                 *mode = SVAL(state->data, 32);
822         }
823         if (size) {
824                 *size = IVAL2_TO_SMB_BIG_UINT(state->data,48);
825         }
826         if (ino) {
827                 *ino = IVAL(state->data, 64);
828         }
829         return NT_STATUS_OK;
830 }
831
832 NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname,
833                         struct timespec *create_time,
834                         struct timespec *access_time,
835                         struct timespec *write_time,
836                         struct timespec *change_time,
837                         SMB_OFF_T *size, uint16 *mode,
838                         SMB_INO_T *ino)
839 {
840         TALLOC_CTX *frame = talloc_stackframe();
841         struct event_context *ev;
842         struct tevent_req *req;
843         NTSTATUS status = NT_STATUS_NO_MEMORY;
844
845         if (cli_has_async_calls(cli)) {
846                 /*
847                  * Can't use sync call while an async call is in flight
848                  */
849                 status = NT_STATUS_INVALID_PARAMETER;
850                 goto fail;
851         }
852         ev = event_context_init(frame);
853         if (ev == NULL) {
854                 goto fail;
855         }
856         req = cli_qpathinfo2_send(frame, ev, cli, fname);
857         if (req == NULL) {
858                 goto fail;
859         }
860         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
861                 goto fail;
862         }
863         status = cli_qpathinfo2_recv(req, create_time, access_time,
864                                      write_time, change_time, size, mode, ino);
865  fail:
866         TALLOC_FREE(frame);
867         if (!NT_STATUS_IS_OK(status)) {
868                 cli_set_error(cli, status);
869         }
870         return status;
871 }
872
873 /****************************************************************************
874  Get the stream info
875 ****************************************************************************/
876
877 static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *data,
878                                size_t data_len,
879                                unsigned int *pnum_streams,
880                                struct stream_struct **pstreams);
881
882 struct cli_qpathinfo_streams_state {
883         uint32_t num_data;
884         uint8_t *data;
885 };
886
887 static void cli_qpathinfo_streams_done(struct tevent_req *subreq);
888
889 struct tevent_req *cli_qpathinfo_streams_send(TALLOC_CTX *mem_ctx,
890                                               struct tevent_context *ev,
891                                               struct cli_state *cli,
892                                               const char *fname)
893 {
894         struct tevent_req *req = NULL, *subreq = NULL;
895         struct cli_qpathinfo_streams_state *state = NULL;
896
897         req = tevent_req_create(mem_ctx, &state,
898                                 struct cli_qpathinfo_streams_state);
899         if (req == NULL) {
900                 return NULL;
901         }
902         subreq = cli_qpathinfo_send(state, ev, cli, fname,
903                                     SMB_FILE_STREAM_INFORMATION,
904                                     0, cli->max_xmit);
905         if (tevent_req_nomem(subreq, req)) {
906                 return tevent_req_post(req, ev);
907         }
908         tevent_req_set_callback(subreq, cli_qpathinfo_streams_done, req);
909         return req;
910 }
911
912 static void cli_qpathinfo_streams_done(struct tevent_req *subreq)
913 {
914         struct tevent_req *req = tevent_req_callback_data(
915                 subreq, struct tevent_req);
916         struct cli_qpathinfo_streams_state *state = tevent_req_data(
917                 req, struct cli_qpathinfo_streams_state);
918         NTSTATUS status;
919
920         status = cli_qpathinfo_recv(subreq, state, &state->data,
921                                     &state->num_data);
922         TALLOC_FREE(subreq);
923         if (!NT_STATUS_IS_OK(status)) {
924                 tevent_req_nterror(req, status);
925                 return;
926         }
927         tevent_req_done(req);
928 }
929
930 NTSTATUS cli_qpathinfo_streams_recv(struct tevent_req *req,
931                                     TALLOC_CTX *mem_ctx,
932                                     unsigned int *pnum_streams,
933                                     struct stream_struct **pstreams)
934 {
935         struct cli_qpathinfo_streams_state *state = tevent_req_data(
936                 req, struct cli_qpathinfo_streams_state);
937         NTSTATUS status;
938
939         if (tevent_req_is_nterror(req, &status)) {
940                 return status;
941         }
942         if (!parse_streams_blob(mem_ctx, state->data, state->num_data,
943                                 pnum_streams, pstreams)) {
944                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
945         }
946         return NT_STATUS_OK;
947 }
948
949 NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
950                                TALLOC_CTX *mem_ctx,
951                                unsigned int *pnum_streams,
952                                struct stream_struct **pstreams)
953 {
954         TALLOC_CTX *frame = talloc_stackframe();
955         struct event_context *ev;
956         struct tevent_req *req;
957         NTSTATUS status = NT_STATUS_NO_MEMORY;
958
959         if (cli_has_async_calls(cli)) {
960                 /*
961                  * Can't use sync call while an async call is in flight
962                  */
963                 status = NT_STATUS_INVALID_PARAMETER;
964                 goto fail;
965         }
966         ev = event_context_init(frame);
967         if (ev == NULL) {
968                 goto fail;
969         }
970         req = cli_qpathinfo_streams_send(frame, ev, cli, fname);
971         if (req == NULL) {
972                 goto fail;
973         }
974         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
975                 goto fail;
976         }
977         status = cli_qpathinfo_streams_recv(req, mem_ctx, pnum_streams,
978                                             pstreams);
979  fail:
980         TALLOC_FREE(frame);
981         if (!NT_STATUS_IS_OK(status)) {
982                 cli_set_error(cli, status);
983         }
984         return status;
985 }
986
987 static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata,
988                                size_t data_len,
989                                unsigned int *pnum_streams,
990                                struct stream_struct **pstreams)
991 {
992         unsigned int num_streams;
993         struct stream_struct *streams;
994         unsigned int ofs;
995
996         num_streams = 0;
997         streams = NULL;
998         ofs = 0;
999
1000         while ((data_len > ofs) && (data_len - ofs >= 24)) {
1001                 uint32_t nlen, len;
1002                 size_t size;
1003                 void *vstr;
1004                 struct stream_struct *tmp;
1005                 uint8_t *tmp_buf;
1006
1007                 tmp = TALLOC_REALLOC_ARRAY(mem_ctx, streams,
1008                                            struct stream_struct,
1009                                            num_streams+1);
1010
1011                 if (tmp == NULL) {
1012                         goto fail;
1013                 }
1014                 streams = tmp;
1015
1016                 nlen                      = IVAL(rdata, ofs + 0x04);
1017
1018                 streams[num_streams].size = IVAL_TO_SMB_OFF_T(
1019                         rdata, ofs + 0x08);
1020                 streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
1021                         rdata, ofs + 0x10);
1022
1023                 if (nlen > data_len - (ofs + 24)) {
1024                         goto fail;
1025                 }
1026
1027                 /*
1028                  * We need to null-terminate src, how do I do this with
1029                  * convert_string_talloc??
1030                  */
1031
1032                 tmp_buf = TALLOC_ARRAY(streams, uint8_t, nlen+2);
1033                 if (tmp_buf == NULL) {
1034                         goto fail;
1035                 }
1036
1037                 memcpy(tmp_buf, rdata+ofs+24, nlen);
1038                 tmp_buf[nlen] = 0;
1039                 tmp_buf[nlen+1] = 0;
1040
1041                 if (!convert_string_talloc(streams, CH_UTF16, CH_UNIX, tmp_buf,
1042                                            nlen+2, &vstr, &size))
1043                 {
1044                         TALLOC_FREE(tmp_buf);
1045                         goto fail;
1046                 }
1047
1048                 TALLOC_FREE(tmp_buf);
1049                 streams[num_streams].name = (char *)vstr;
1050                 num_streams++;
1051
1052                 len = IVAL(rdata, ofs);
1053                 if (len > data_len - ofs) {
1054                         goto fail;
1055                 }
1056                 if (len == 0) break;
1057                 ofs += len;
1058         }
1059
1060         *pnum_streams = num_streams;
1061         *pstreams = streams;
1062         return true;
1063
1064  fail:
1065         TALLOC_FREE(streams);
1066         return false;
1067 }
1068
1069 /****************************************************************************
1070  Send a qfileinfo QUERY_FILE_NAME_INFO call.
1071 ****************************************************************************/
1072
1073 NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum, char *name,
1074                        size_t namelen)
1075 {
1076         uint8_t *rdata;
1077         uint32_t num_rdata;
1078         NTSTATUS status;
1079
1080         status = cli_qfileinfo(talloc_tos(), cli, fnum,
1081                                SMB_QUERY_FILE_NAME_INFO,
1082                                4, cli->max_xmit,
1083                                &rdata, &num_rdata);
1084         if (!NT_STATUS_IS_OK(status)) {
1085                 return status;
1086         }
1087
1088         clistr_pull(cli->inbuf, name, rdata+4, namelen, IVAL(rdata, 0),
1089                     STR_UNICODE);
1090         TALLOC_FREE(rdata);
1091         return NT_STATUS_OK;
1092 }
1093
1094 /****************************************************************************
1095  Send a qfileinfo call.
1096 ****************************************************************************/
1097
1098 NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum,
1099                              uint16 *mode, SMB_OFF_T *size,
1100                              struct timespec *create_time,
1101                              struct timespec *access_time,
1102                              struct timespec *write_time,
1103                              struct timespec *change_time,
1104                              SMB_INO_T *ino)
1105 {
1106         uint8_t *rdata;
1107         uint32_t num_rdata;
1108         NTSTATUS status;
1109
1110         /* if its a win95 server then fail this - win95 totally screws it
1111            up */
1112         if (cli->win95) {
1113                 return NT_STATUS_NOT_SUPPORTED;
1114         }
1115
1116         status = cli_qfileinfo(talloc_tos(), cli, fnum,
1117                                SMB_QUERY_FILE_ALL_INFO,
1118                                68, MIN(cli->max_xmit, 0xffff),
1119                                &rdata, &num_rdata);
1120         if (!NT_STATUS_IS_OK(status)) {
1121                 return status;
1122         }
1123
1124         if (create_time) {
1125                 *create_time = interpret_long_date((char *)rdata+0);
1126         }
1127         if (access_time) {
1128                 *access_time = interpret_long_date((char *)rdata+8);
1129         }
1130         if (write_time) {
1131                 *write_time = interpret_long_date((char *)rdata+16);
1132         }
1133         if (change_time) {
1134                 *change_time = interpret_long_date((char *)rdata+24);
1135         }
1136         if (mode) {
1137                 *mode = SVAL(rdata, 32);
1138         }
1139         if (size) {
1140                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
1141         }
1142         if (ino) {
1143                 *ino = IVAL(rdata, 64);
1144         }
1145
1146         TALLOC_FREE(rdata);
1147         return NT_STATUS_OK;
1148 }
1149
1150 /****************************************************************************
1151  Send a qpathinfo BASIC_INFO call.
1152 ****************************************************************************/
1153
1154 struct cli_qpathinfo_basic_state {
1155         uint32_t num_data;
1156         uint8_t *data;
1157 };
1158
1159 static void cli_qpathinfo_basic_done(struct tevent_req *subreq);
1160
1161 struct tevent_req *cli_qpathinfo_basic_send(TALLOC_CTX *mem_ctx,
1162                                             struct event_context *ev,
1163                                             struct cli_state *cli,
1164                                             const char *fname)
1165 {
1166         struct tevent_req *req = NULL, *subreq = NULL;
1167         struct cli_qpathinfo_basic_state *state = NULL;
1168
1169         req = tevent_req_create(mem_ctx, &state,
1170                                 struct cli_qpathinfo_basic_state);
1171         if (req == NULL) {
1172                 return NULL;
1173         }
1174         subreq = cli_qpathinfo_send(state, ev, cli, fname,
1175                                     SMB_QUERY_FILE_BASIC_INFO,
1176                                     36, cli->max_xmit);
1177         if (tevent_req_nomem(subreq, req)) {
1178                 return tevent_req_post(req, ev);
1179         }
1180         tevent_req_set_callback(subreq, cli_qpathinfo_basic_done, req);
1181         return req;
1182 }
1183
1184 static void cli_qpathinfo_basic_done(struct tevent_req *subreq)
1185 {
1186         struct tevent_req *req = tevent_req_callback_data(
1187                 subreq, struct tevent_req);
1188         struct cli_qpathinfo_basic_state *state = tevent_req_data(
1189                 req, struct cli_qpathinfo_basic_state);
1190         NTSTATUS status;
1191
1192         status = cli_qpathinfo_recv(subreq, state, &state->data,
1193                                     &state->num_data);
1194         TALLOC_FREE(subreq);
1195         if (!NT_STATUS_IS_OK(status)) {
1196                 tevent_req_nterror(req, status);
1197                 return;
1198         }
1199         tevent_req_done(req);
1200 }
1201
1202 NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req,
1203                                   SMB_STRUCT_STAT *sbuf, uint32 *attributes)
1204 {
1205         struct cli_qpathinfo_basic_state *state = tevent_req_data(
1206                 req, struct cli_qpathinfo_basic_state);
1207         NTSTATUS status;
1208
1209         if (tevent_req_is_nterror(req, &status)) {
1210                 return status;
1211         }
1212
1213         sbuf->st_ex_atime = interpret_long_date((char *)state->data+8);
1214         sbuf->st_ex_mtime = interpret_long_date((char *)state->data+16);
1215         sbuf->st_ex_ctime = interpret_long_date((char *)state->data+24);
1216         *attributes = IVAL(state->data, 32);
1217         return NT_STATUS_OK;
1218 }
1219
1220 NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name,
1221                              SMB_STRUCT_STAT *sbuf, uint32 *attributes)
1222 {
1223         TALLOC_CTX *frame = talloc_stackframe();
1224         struct event_context *ev;
1225         struct tevent_req *req;
1226         NTSTATUS status = NT_STATUS_NO_MEMORY;
1227
1228         if (cli_has_async_calls(cli)) {
1229                 /*
1230                  * Can't use sync call while an async call is in flight
1231                  */
1232                 status = NT_STATUS_INVALID_PARAMETER;
1233                 goto fail;
1234         }
1235         ev = event_context_init(frame);
1236         if (ev == NULL) {
1237                 goto fail;
1238         }
1239         req = cli_qpathinfo_basic_send(frame, ev, cli, name);
1240         if (req == NULL) {
1241                 goto fail;
1242         }
1243         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1244                 goto fail;
1245         }
1246         status = cli_qpathinfo_basic_recv(req, sbuf, attributes);
1247  fail:
1248         TALLOC_FREE(frame);
1249         if (!NT_STATUS_IS_OK(status)) {
1250                 cli_set_error(cli, status);
1251         }
1252         return status;
1253 }
1254
1255 /****************************************************************************
1256  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1257 ****************************************************************************/
1258
1259 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1260 {
1261         uint8_t *rdata;
1262         uint32_t num_rdata;
1263         unsigned int len;
1264         char *converted = NULL;
1265         size_t converted_size = 0;
1266         NTSTATUS status;
1267
1268         status = cli_qpathinfo(talloc_tos(), cli, fname,
1269                                SMB_QUERY_FILE_ALT_NAME_INFO,
1270                                4, cli->max_xmit, &rdata, &num_rdata);
1271         if (!NT_STATUS_IS_OK(status)) {
1272                 return status;
1273         }
1274
1275         len = IVAL(rdata, 0);
1276
1277         if (len > num_rdata - 4) {
1278                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1279         }
1280
1281         /* The returned data is a pushed string, not raw data. */
1282         if (!convert_string_talloc(talloc_tos(),
1283                                    cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
1284                                    CH_UNIX,
1285                                    rdata + 4,
1286                                    len,
1287                                    &converted,
1288                                    &converted_size)) {
1289                 return NT_STATUS_NO_MEMORY;
1290         }
1291         fstrcpy(alt_name, converted);
1292
1293         TALLOC_FREE(converted);
1294         TALLOC_FREE(rdata);
1295
1296         return NT_STATUS_OK;
1297 }