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