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