Support fetching very long server lists with RAP_NetServerEnum3.
[bbaumbach/samba-autobuild/.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                         return false;
301                 }
302                 p += len;
303
304                 if (!cli_api(cli,
305                         param, PTR_DIFF(p,param), 8, /* params, length, max */
306                         NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
307                             &rparam, &rprcnt, /* return params, return size */
308                             &rdata, &rdrcnt)) { /* return data, return size */
309
310                         /* break out of the loop on error */
311                         res = -1;
312                         break;
313                 }
314
315                 rdata_end = rdata + rdrcnt;
316                 res = rparam ? SVAL(rparam,0) : -1;
317
318                 if (res == 0 || res == ERRmoredata ||
319                     (res != -1 && cli_errno(cli) == 0)) {
320                         char *sname = NULL;
321                         int i, count;
322                         int converter=SVAL(rparam,2);
323
324                         /* Get the number of items returned in this buffer */
325                         count = SVAL(rparam, 4);
326
327                         /* The next field contains the number of items left,
328                          * including those returned in this buffer. So the
329                          * first time through this should contain all of the
330                          * entries.
331                          */
332                         if (total_cnt == 0) {
333                                 total_cnt = SVAL(rparam, 6);
334                         }
335
336                         /* Keep track of how many we have read */
337                         return_cnt += count;
338                         p = rdata;
339
340                         /* The last name in the previous NetServerEnum reply is
341                          * sent back to server in the NetServerEnum3 request
342                          * (last_entry). The next reply should repeat this entry
343                          * as the first element. We have no proof that this is
344                          * always true, but from traces that seems to be the
345                          * behavior from Window Servers. So first lets do a lot
346                          * of checking, just being paranoid. If the string
347                          * matches then we already saw this entry so skip it.
348                          *
349                          * NOTE: sv1_name field must be null terminated and has
350                          * a max size of 16 (NetBIOS Name).
351                          */
352                         if (last_entry && count && p &&
353                                 (strncmp(last_entry, p, 16) == 0)) {
354                             count -= 1; /* Skip this entry */
355                             return_cnt = -1; /* Not part of total, so don't count. */
356                             p = rdata + 26; /* Skip the whole record */
357                         }
358
359                         for (i = 0; i < count; i++, p += 26) {
360                                 int comment_offset;
361                                 const char *cmnt;
362                                 const char *p1;
363                                 char *s1, *s2;
364                                 TALLOC_CTX *frame = talloc_stackframe();
365
366                                 if (p + 26 > rdata_end) {
367                                         TALLOC_FREE(frame);
368                                         break;
369                                 }
370
371                                 sname = p;
372                                 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
373                                 cmnt = comment_offset?(rdata+comment_offset):"";
374
375                                 if (comment_offset < 0 || comment_offset > (int)rdrcnt) {
376                                         TALLOC_FREE(frame);
377                                         continue;
378                                 }
379
380                                 /* Work out the comment length. */
381                                 for (p1 = cmnt, len = 0; *p1 &&
382                                                 p1 < rdata_end; len++)
383                                         p1++;
384                                 if (!*p1) {
385                                         len++;
386                                 }
387
388                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
389
390                                 pull_string_talloc(frame,rdata,0,
391                                         &s1,sname,16,STR_ASCII);
392                                 pull_string_talloc(frame,rdata,0,
393                                         &s2,cmnt,len,STR_ASCII);
394
395                                 if (!s1 || !s2) {
396                                         TALLOC_FREE(frame);
397                                         continue;
398                                 }
399
400                                 fn(s1, stype, s2, state);
401                                 TALLOC_FREE(frame);
402                         }
403
404                         /* We are done with the old last entry, so now we can free it */
405                         if (last_entry) {
406                                 SAFE_FREE(last_entry); /* This will set it to null */
407                         }
408
409                         /* We always make a copy of  the last entry if we have one */
410                         if (sname) {
411                                 last_entry = smb_xstrdup(sname);
412                         }
413
414                         /* If we have more data, but no last entry then error out */
415                         if (!last_entry && (res == ERRmoredata)) {
416                                 errno = EINVAL;
417                                 res = 0;
418                         }
419
420                 }
421
422                 SAFE_FREE(rparam);
423                 SAFE_FREE(rdata);
424         } while ((res == ERRmoredata) && (total_cnt > return_cnt));
425
426         SAFE_FREE(rparam);
427         SAFE_FREE(rdata);
428         SAFE_FREE(last_entry);
429
430         if (res == -1) {
431                 errno = cli_errno(cli);
432         } else {
433                 if (!return_cnt) {
434                         /* this is a very special case, when the domain master for the
435                            work group isn't part of the work group itself, there is something
436                            wild going on */
437                         errno = ENOENT;
438                 }
439             }
440
441         return(return_cnt > 0);
442 }
443
444 /****************************************************************************
445  Send a SamOEMChangePassword command.
446 ****************************************************************************/
447
448 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
449                              const char *old_password)
450 {
451         char param[1024];
452         unsigned char data[532];
453         char *p = param;
454         unsigned char old_pw_hash[16];
455         unsigned char new_pw_hash[16];
456         unsigned int data_len;
457         unsigned int param_len = 0;
458         char *rparam = NULL;
459         char *rdata = NULL;
460         unsigned int rprcnt, rdrcnt;
461
462         if (strlen(user) >= sizeof(fstring)-1) {
463                 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
464                 return False;
465         }
466
467         SSVAL(p,0,214); /* SamOEMChangePassword command. */
468         p += 2;
469         strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
470         p = skip_string(param,sizeof(param),p);
471         strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
472         p = skip_string(param,sizeof(param),p);
473         strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
474         p = skip_string(param,sizeof(param),p);
475         SSVAL(p,0,532);
476         p += 2;
477
478         param_len = PTR_DIFF(p,param);
479
480         /*
481          * Get the Lanman hash of the old password, we
482          * use this as the key to make_oem_passwd_hash().
483          */
484         E_deshash(old_password, old_pw_hash);
485
486         encode_pw_buffer(data, new_password, STR_ASCII);
487
488 #ifdef DEBUG_PASSWORD
489         DEBUG(100,("make_oem_passwd_hash\n"));
490         dump_data(100, data, 516);
491 #endif
492         SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
493
494         /*
495          * Now place the old password hash in the data.
496          */
497         E_deshash(new_password, new_pw_hash);
498
499         E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
500
501         data_len = 532;
502
503         if (cli_send_trans(cli,SMBtrans,
504                     PIPE_LANMAN,                          /* name */
505                     0,0,                                  /* fid, flags */
506                     NULL,0,0,                             /* setup, length, max */
507                     param,param_len,2,                    /* param, length, max */
508                     (char *)data,data_len,0                       /* data, length, max */
509                    ) == False) {
510                 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
511                         user ));
512                 return False;
513         }
514
515         if (!cli_receive_trans(cli,SMBtrans,
516                        &rparam, &rprcnt,
517                        &rdata, &rdrcnt)) {
518                 DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
519                         user ));
520                 return False;
521         }
522
523         if (rparam) {
524                 cli->rap_error = SVAL(rparam,0);
525         }
526
527         SAFE_FREE(rparam);
528         SAFE_FREE(rdata);
529
530         return (cli->rap_error == 0);
531 }
532
533 /****************************************************************************
534  Send a qpathinfo call.
535 ****************************************************************************/
536
537 bool cli_qpathinfo(struct cli_state *cli,
538                         const char *fname,
539                         time_t *change_time,
540                         time_t *access_time,
541                         time_t *write_time,
542                         SMB_OFF_T *size,
543                         uint16 *mode)
544 {
545         unsigned int data_len = 0;
546         unsigned int param_len = 0;
547         unsigned int rparam_len, rdata_len;
548         uint16 setup = TRANSACT2_QPATHINFO;
549         char *param;
550         char *rparam=NULL, *rdata=NULL;
551         int count=8;
552         bool ret;
553         time_t (*date_fn)(struct cli_state *, const void *);
554         char *p;
555         size_t nlen = 2*(strlen(fname)+1);
556
557         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
558         if (!param) {
559                 return false;
560         }
561         p = param;
562         memset(p, '\0', 6);
563         SSVAL(p, 0, SMB_INFO_STANDARD);
564         p += 6;
565         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
566         param_len = PTR_DIFF(p, param);
567
568         do {
569                 ret = (cli_send_trans(cli, SMBtrans2,
570                                       NULL,           /* Name */
571                                       -1, 0,          /* fid, flags */
572                                       &setup, 1, 0,   /* setup, length, max */
573                                       param, param_len, 10, /* param, length, max */
574                                       NULL, data_len, cli->max_xmit /* data, length, max */
575                                       ) &&
576                        cli_receive_trans(cli, SMBtrans2,
577                                          &rparam, &rparam_len,
578                                          &rdata, &rdata_len));
579                 if (!cli_is_dos_error(cli)) break;
580                 if (!ret) {
581                         /* we need to work around a Win95 bug - sometimes
582                            it gives ERRSRV/ERRerror temprarily */
583                         uint8 eclass;
584                         uint32 ecode;
585                         cli_dos_error(cli, &eclass, &ecode);
586                         if (eclass != ERRSRV || ecode != ERRerror) break;
587                         smb_msleep(100);
588                 }
589         } while (count-- && ret==False);
590
591         SAFE_FREE(param);
592         if (!ret || !rdata || rdata_len < 22) {
593                 return False;
594         }
595
596         if (cli->win95) {
597                 date_fn = cli_make_unix_date;
598         } else {
599                 date_fn = cli_make_unix_date2;
600         }
601
602         if (change_time) {
603                 *change_time = date_fn(cli, rdata+0);
604         }
605         if (access_time) {
606                 *access_time = date_fn(cli, rdata+4);
607         }
608         if (write_time) {
609                 *write_time = date_fn(cli, rdata+8);
610         }
611         if (size) {
612                 *size = IVAL(rdata, 12);
613         }
614         if (mode) {
615                 *mode = SVAL(rdata,l1_attrFile);
616         }
617
618         SAFE_FREE(rdata);
619         SAFE_FREE(rparam);
620         return True;
621 }
622
623 /****************************************************************************
624  Send a setpathinfo call.
625 ****************************************************************************/
626
627 bool cli_setpathinfo(struct cli_state *cli, const char *fname,
628                      time_t create_time,
629                      time_t access_time,
630                      time_t write_time,
631                      time_t change_time,
632                      uint16 mode)
633 {
634         unsigned int data_len = 0;
635         unsigned int param_len = 0;
636         unsigned int rparam_len, rdata_len;
637         uint16 setup = TRANSACT2_SETPATHINFO;
638         char *param;
639         char data[40];
640         char *rparam=NULL, *rdata=NULL;
641         int count=8;
642         bool ret;
643         char *p;
644         size_t nlen = 2*(strlen(fname)+1);
645
646         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
647         if (!param) {
648                 return false;
649         }
650         memset(param, '\0', 6);
651         memset(data, 0, sizeof(data));
652
653         p = param;
654
655         /* Add the information level */
656         SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
657
658         /* Skip reserved */
659         p += 6;
660
661         /* Add the file name */
662         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
663
664         param_len = PTR_DIFF(p, param);
665
666         p = data;
667
668         /*
669          * Add the create, last access, modification, and status change times
670          */
671         put_long_date(p, create_time);
672         p += 8;
673
674         put_long_date(p, access_time);
675         p += 8;
676
677         put_long_date(p, write_time);
678         p += 8;
679
680         put_long_date(p, change_time);
681         p += 8;
682
683         /* Add attributes */
684         SIVAL(p, 0, mode);
685         p += 4;
686
687         /* Add padding */
688         SIVAL(p, 0, 0);
689         p += 4;
690
691         data_len = PTR_DIFF(p, data);
692
693         do {
694                 ret = (cli_send_trans(cli, SMBtrans2,
695                                       NULL,           /* Name */
696                                       -1, 0,          /* fid, flags */
697                                       &setup, 1, 0,   /* setup, length, max */
698                                       param, param_len, 10, /* param, length, max */
699                                       data, data_len, cli->max_xmit /* data, length, max */
700                                       ) &&
701                        cli_receive_trans(cli, SMBtrans2,
702                                          &rparam, &rparam_len,
703                                          &rdata, &rdata_len));
704                 if (!cli_is_dos_error(cli)) break;
705                 if (!ret) {
706                         /* we need to work around a Win95 bug - sometimes
707                            it gives ERRSRV/ERRerror temprarily */
708                         uint8 eclass;
709                         uint32 ecode;
710                         cli_dos_error(cli, &eclass, &ecode);
711                         if (eclass != ERRSRV || ecode != ERRerror) break;
712                         smb_msleep(100);
713                 }
714         } while (count-- && ret==False);
715
716         SAFE_FREE(param);
717         if (!ret) {
718                 return False;
719         }
720
721         SAFE_FREE(rdata);
722         SAFE_FREE(rparam);
723         return True;
724 }
725
726 /****************************************************************************
727  Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
728 ****************************************************************************/
729
730 bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
731                     struct timespec *create_time,
732                     struct timespec *access_time,
733                     struct timespec *write_time,
734                     struct timespec *change_time,
735                     SMB_OFF_T *size, uint16 *mode,
736                     SMB_INO_T *ino)
737 {
738         unsigned int data_len = 0;
739         unsigned int param_len = 0;
740         uint16 setup = TRANSACT2_QPATHINFO;
741         char *param;
742         char *rparam=NULL, *rdata=NULL;
743         char *p;
744         size_t nlen = 2*(strlen(fname)+1);
745
746         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
747         if (!param) {
748                 return false;
749         }
750         p = param;
751         memset(param, '\0', 6);
752         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
753         p += 6;
754         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
755
756         param_len = PTR_DIFF(p, param);
757
758         if (!cli_send_trans(cli, SMBtrans2,
759                             NULL,                         /* name */
760                             -1, 0,                        /* fid, flags */
761                             &setup, 1, 0,                 /* setup, length, max */
762                             param, param_len, 10,         /* param, length, max */
763                             NULL, data_len, cli->max_xmit /* data, length, max */
764                            )) {
765                 SAFE_FREE(param);
766                 return False;
767         }
768
769         SAFE_FREE(param);
770         if (!cli_receive_trans(cli, SMBtrans2,
771                                &rparam, &param_len,
772                                &rdata, &data_len)) {
773                 return False;
774         }
775
776         if (!rdata || data_len < 22) {
777                 return False;
778         }
779
780         if (create_time) {
781                 *create_time = interpret_long_date(rdata+0);
782         }
783         if (access_time) {
784                 *access_time = interpret_long_date(rdata+8);
785         }
786         if (write_time) {
787                 *write_time = interpret_long_date(rdata+16);
788         }
789         if (change_time) {
790                 *change_time = interpret_long_date(rdata+24);
791         }
792         if (mode) {
793                 *mode = SVAL(rdata, 32);
794         }
795         if (size) {
796                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
797         }
798         if (ino) {
799                 *ino = IVAL(rdata, 64);
800         }
801
802         SAFE_FREE(rdata);
803         SAFE_FREE(rparam);
804         return True;
805 }
806
807 /****************************************************************************
808  Send a qfileinfo QUERY_FILE_NAME_INFO call.
809 ****************************************************************************/
810
811 bool cli_qfilename(struct cli_state *cli, int fnum, char *name, size_t namelen)
812 {
813         unsigned int data_len = 0;
814         unsigned int param_len = 0;
815         uint16 setup = TRANSACT2_QFILEINFO;
816         char param[4];
817         char *rparam=NULL, *rdata=NULL;
818
819         param_len = 4;
820         SSVAL(param, 0, fnum);
821         SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
822
823         if (!cli_send_trans(cli, SMBtrans2,
824                             NULL,                         /* name */
825                             -1, 0,                        /* fid, flags */
826                             &setup, 1, 0,                 /* setup, length, max */
827                             param, param_len, 2,          /* param, length, max */
828                             NULL, data_len, cli->max_xmit /* data, length, max */
829                            )) {
830                 return False;
831         }
832
833         if (!cli_receive_trans(cli, SMBtrans2,
834                                &rparam, &param_len,
835                                &rdata, &data_len)) {
836                 return False;
837         }
838
839         if (!rdata || data_len < 4) {
840                 return False;
841         }
842
843         clistr_pull(cli, name, rdata+4, namelen, IVAL(rdata, 0), STR_UNICODE);
844
845         return True;
846 }
847
848 /****************************************************************************
849  Send a qfileinfo call.
850 ****************************************************************************/
851
852 bool cli_qfileinfo(struct cli_state *cli, int fnum,
853                    uint16 *mode, SMB_OFF_T *size,
854                    struct timespec *create_time,
855                    struct timespec *access_time,
856                    struct timespec *write_time,
857                    struct timespec *change_time,
858                    SMB_INO_T *ino)
859 {
860         unsigned int data_len = 0;
861         unsigned int param_len = 0;
862         uint16 setup = TRANSACT2_QFILEINFO;
863         char param[4];
864         char *rparam=NULL, *rdata=NULL;
865
866         /* if its a win95 server then fail this - win95 totally screws it
867            up */
868         if (cli->win95) return False;
869
870         param_len = 4;
871
872         SSVAL(param, 0, fnum);
873         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
874
875         if (!cli_send_trans(cli, SMBtrans2,
876                             NULL,                         /* name */
877                             -1, 0,                        /* fid, flags */
878                             &setup, 1, 0,                 /* setup, length, max */
879                             param, param_len, 2,          /* param, length, max */
880                             NULL, data_len, cli->max_xmit /* data, length, max */
881                            )) {
882                 return False;
883         }
884
885         if (!cli_receive_trans(cli, SMBtrans2,
886                                &rparam, &param_len,
887                                &rdata, &data_len)) {
888                 return False;
889         }
890
891         if (!rdata || data_len < 68) {
892                 return False;
893         }
894
895         if (create_time) {
896                 *create_time = interpret_long_date(rdata+0);
897         }
898         if (access_time) {
899                 *access_time = interpret_long_date(rdata+8);
900         }
901         if (write_time) {
902                 *write_time = interpret_long_date(rdata+16);
903         }
904         if (change_time) {
905                 *change_time = interpret_long_date(rdata+24);
906         }
907         if (mode) {
908                 *mode = SVAL(rdata, 32);
909         }
910         if (size) {
911                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
912         }
913         if (ino) {
914                 *ino = IVAL(rdata, 64);
915         }
916
917         SAFE_FREE(rdata);
918         SAFE_FREE(rparam);
919         return True;
920 }
921
922 /****************************************************************************
923  Send a qpathinfo BASIC_INFO call.
924 ****************************************************************************/
925
926 bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
927                           SMB_STRUCT_STAT *sbuf, uint32 *attributes )
928 {
929         unsigned int param_len = 0;
930         unsigned int data_len = 0;
931         uint16 setup = TRANSACT2_QPATHINFO;
932         char *param;
933         char *rparam=NULL, *rdata=NULL;
934         char *p;
935         char *path;
936         int len;
937         size_t nlen;
938         TALLOC_CTX *frame = talloc_stackframe();
939
940         path = talloc_strdup(frame, name);
941         if (!path) {
942                 TALLOC_FREE(frame);
943                 return false;
944         }
945         /* cleanup */
946
947         len = strlen(path);
948         if ( path[len-1] == '\\' || path[len-1] == '/') {
949                 path[len-1] = '\0';
950         }
951         nlen = 2*(strlen(path)+1);
952
953         param = TALLOC_ARRAY(frame,char,6+nlen+2);
954         if (!param) {
955                 return false;
956         }
957         p = param;
958         memset(param, '\0', 6);
959
960         SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
961         p += 6;
962         p += clistr_push(cli, p, path, nlen, STR_TERMINATE);
963         param_len = PTR_DIFF(p, param);
964
965
966         if (!cli_send_trans(cli, SMBtrans2,
967                         NULL,                        /* name */
968                         -1, 0,                       /* fid, flags */
969                         &setup, 1, 0,                /* setup, length, max */
970                         param, param_len, 2,         /* param, length, max */
971                         NULL,  0, cli->max_xmit      /* data, length, max */
972                         )) {
973                 TALLOC_FREE(frame);
974                 return False;
975         }
976
977         TALLOC_FREE(frame);
978
979         if (!cli_receive_trans(cli, SMBtrans2,
980                 &rparam, &param_len,
981                 &rdata, &data_len)) {
982                         return False;
983         }
984
985         if (data_len < 36) {
986                 SAFE_FREE(rdata);
987                 SAFE_FREE(rparam);
988                 return False;
989         }
990
991         set_atimespec(sbuf, interpret_long_date( rdata+8 )); /* Access time. */
992         set_mtimespec(sbuf, interpret_long_date( rdata+16 )); /* Write time. */
993         set_ctimespec(sbuf, interpret_long_date( rdata+24 )); /* Change time. */
994
995         *attributes = IVAL( rdata, 32 );
996
997         SAFE_FREE(rparam);
998         SAFE_FREE(rdata);
999
1000         return True;
1001 }
1002
1003 /****************************************************************************
1004  Send a qfileinfo call.
1005 ****************************************************************************/
1006
1007 bool cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
1008 {
1009         unsigned int data_len = 0;
1010         unsigned int param_len = 0;
1011         uint16 setup = TRANSACT2_QFILEINFO;
1012         char param[4];
1013         char *rparam=NULL, *rdata=NULL;
1014
1015         *poutdata = NULL;
1016         *poutlen = 0;
1017
1018         /* if its a win95 server then fail this - win95 totally screws it
1019            up */
1020         if (cli->win95)
1021                 return False;
1022
1023         param_len = 4;
1024
1025         SSVAL(param, 0, fnum);
1026         SSVAL(param, 2, level);
1027
1028         if (!cli_send_trans(cli, SMBtrans2,
1029                             NULL,                           /* name */
1030                             -1, 0,                          /* fid, flags */
1031                             &setup, 1, 0,                   /* setup, length, max */
1032                             param, param_len, 2,            /* param, length, max */
1033                             NULL, data_len, cli->max_xmit   /* data, length, max */
1034                            )) {
1035                 return False;
1036         }
1037
1038         if (!cli_receive_trans(cli, SMBtrans2,
1039                                &rparam, &param_len,
1040                                &rdata, &data_len)) {
1041                 return False;
1042         }
1043
1044         *poutdata = (char *)memdup(rdata, data_len);
1045         if (!*poutdata) {
1046                 SAFE_FREE(rdata);
1047                 SAFE_FREE(rparam);
1048                 return False;
1049         }
1050
1051         *poutlen = data_len;
1052
1053         SAFE_FREE(rdata);
1054         SAFE_FREE(rparam);
1055         return True;
1056 }
1057
1058 /****************************************************************************
1059  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
1060 ****************************************************************************/
1061
1062 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
1063 {
1064         unsigned int data_len = 0;
1065         unsigned int param_len = 0;
1066         uint16 setup = TRANSACT2_QPATHINFO;
1067         char *param;
1068         char *rparam=NULL, *rdata=NULL;
1069         int count=8;
1070         char *p;
1071         bool ret;
1072         unsigned int len;
1073         size_t nlen = 2*(strlen(fname)+1);
1074
1075         param = SMB_MALLOC_ARRAY(char, 6+nlen+2);
1076         if (!param) {
1077                 return NT_STATUS_NO_MEMORY;
1078         }
1079         p = param;
1080         memset(param, '\0', 6);
1081         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
1082         p += 6;
1083         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
1084         param_len = PTR_DIFF(p, param);
1085
1086         do {
1087                 ret = (cli_send_trans(cli, SMBtrans2,
1088                                       NULL,           /* Name */
1089                                       -1, 0,          /* fid, flags */
1090                                       &setup, 1, 0,   /* setup, length, max */
1091                                       param, param_len, 10, /* param, length, max */
1092                                       NULL, data_len, cli->max_xmit /* data, length, max */
1093                                       ) &&
1094                        cli_receive_trans(cli, SMBtrans2,
1095                                          &rparam, &param_len,
1096                                          &rdata, &data_len));
1097                 if (!ret && cli_is_dos_error(cli)) {
1098                         /* we need to work around a Win95 bug - sometimes
1099                            it gives ERRSRV/ERRerror temprarily */
1100                         uint8 eclass;
1101                         uint32 ecode;
1102                         cli_dos_error(cli, &eclass, &ecode);
1103                         if (eclass != ERRSRV || ecode != ERRerror) break;
1104                         smb_msleep(100);
1105                 }
1106         } while (count-- && ret==False);
1107
1108         SAFE_FREE(param);
1109
1110         if (!ret || !rdata || data_len < 4) {
1111                 return NT_STATUS_UNSUCCESSFUL;
1112         }
1113
1114         len = IVAL(rdata, 0);
1115
1116         if (len > data_len - 4) {
1117                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1118         }
1119
1120         clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
1121
1122         SAFE_FREE(rdata);
1123         SAFE_FREE(rparam);
1124
1125         return NT_STATUS_OK;
1126 }