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