Remove arbitrary 1k limit on pathnames. Malloc them.
[ira/wip.git] / source3 / libsmb / clirap.c
1 /*
2    Unix SMB/CIFS implementation.
3    client RAP calls
4    Copyright (C) Andrew Tridgell         1994-1998
5    Copyright (C) Gerald (Jerry) Carter   2004
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22
23 /****************************************************************************
24  Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
25 ****************************************************************************/
26
27 bool cli_api_pipe(struct cli_state *cli, const char *pipe_name,
28                   uint16 *setup, uint32 setup_count, uint32 max_setup_count,
29                   char *params, uint32 param_count, uint32 max_param_count,
30                   char *data, uint32 data_count, uint32 max_data_count,
31                   char **rparam, uint32 *rparam_count,
32                   char **rdata, uint32 *rdata_count)
33 {
34         cli_send_trans(cli, SMBtrans,
35                  pipe_name,
36                  0,0,                         /* fid, flags */
37                  setup, setup_count, max_setup_count,
38                  params, param_count, max_param_count,
39                  data, data_count, max_data_count);
40
41         return (cli_receive_trans(cli, SMBtrans,
42                             rparam, (unsigned int *)rparam_count,
43                             rdata, (unsigned int *)rdata_count));
44 }
45
46 /****************************************************************************
47  Call a remote api
48 ****************************************************************************/
49
50 bool cli_api(struct cli_state *cli,
51              char *param, int prcnt, int mprcnt,
52              char *data, int drcnt, int mdrcnt,
53              char **rparam, unsigned int *rprcnt,
54              char **rdata, unsigned int *rdrcnt)
55 {
56         cli_send_trans(cli,SMBtrans,
57                  PIPE_LANMAN,             /* Name */
58                  0,0,                     /* fid, flags */
59                  NULL,0,0,                /* Setup, length, max */
60                  param, prcnt, mprcnt,    /* Params, length, max */
61                  data, drcnt, mdrcnt      /* Data, length, max */
62                 );
63
64         return (cli_receive_trans(cli,SMBtrans,
65                             rparam, rprcnt,
66                             rdata, rdrcnt));
67 }
68
69 /****************************************************************************
70  Perform a NetWkstaUserLogon.
71 ****************************************************************************/
72
73 bool cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
74 {
75         char *rparam = NULL;
76         char *rdata = NULL;
77         char *p;
78         unsigned int rdrcnt,rprcnt;
79         char param[1024];
80
81         memset(param, 0, sizeof(param));
82
83         /* send a SMBtrans command with api NetWkstaUserLogon */
84         p = param;
85         SSVAL(p,0,132); /* api number */
86         p += 2;
87         strlcpy(p,"OOWb54WrLh",sizeof(param)-PTR_DIFF(p,param));
88         p = skip_string(param,sizeof(param),p);
89         strlcpy(p,"WB21BWDWWDDDDDDDzzzD",sizeof(param)-PTR_DIFF(p,param));
90         p = skip_string(param,sizeof(param),p);
91         SSVAL(p,0,1);
92         p += 2;
93         strlcpy(p,user,sizeof(param)-PTR_DIFF(p,param));
94         strupper_m(p);
95         p += 21;
96         p++;
97         p += 15;
98         p++;
99         strlcpy(p, workstation,sizeof(param)-PTR_DIFF(p,param));
100         strupper_m(p);
101         p += 16;
102         SSVAL(p, 0, CLI_BUFFER_SIZE);
103         p += 2;
104         SSVAL(p, 0, CLI_BUFFER_SIZE);
105         p += 2;
106
107         if (cli_api(cli,
108                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
109                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
110                     &rparam, &rprcnt,               /* return params, return size */
111                     &rdata, &rdrcnt                 /* return data, return size */
112                    )) {
113                 cli->rap_error = rparam? SVAL(rparam,0) : -1;
114                 p = rdata;
115
116                 if (cli->rap_error == 0) {
117                         DEBUG(4,("NetWkstaUserLogon success\n"));
118                         cli->privileges = SVAL(p, 24);
119                         /* The cli->eff_name field used to be set here
120                            but it wasn't used anywhere else. */
121                 } else {
122                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
123                 }
124         }
125
126         SAFE_FREE(rparam);
127         SAFE_FREE(rdata);
128         return (cli->rap_error == 0);
129 }
130
131 /****************************************************************************
132  Call a NetShareEnum - try and browse available connections on a host.
133 ****************************************************************************/
134
135 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state)
136 {
137         char *rparam = NULL;
138         char *rdata = NULL;
139         char *p;
140         unsigned int rdrcnt,rprcnt;
141         char param[1024];
142         int count = -1;
143
144         /* now send a SMBtrans command with api RNetShareEnum */
145         p = param;
146         SSVAL(p,0,0); /* api number */
147         p += 2;
148         strlcpy(p,"WrLeh",sizeof(param)-PTR_DIFF(p,param));
149         p = skip_string(param,sizeof(param),p);
150         strlcpy(p,"B13BWz",sizeof(param)-PTR_DIFF(p,param));
151         p = skip_string(param,sizeof(param),p);
152         SSVAL(p,0,1);
153         /*
154          * Win2k needs a *smaller* buffer than 0xFFFF here -
155          * it returns "out of server memory" with 0xFFFF !!! JRA.
156          */
157         SSVAL(p,2,0xFFE0);
158         p += 4;
159
160         if (cli_api(cli,
161                     param, PTR_DIFF(p,param), 1024,  /* Param, length, maxlen */
162                     NULL, 0, 0xFFE0,            /* data, length, maxlen - Win2k needs a small buffer here too ! */
163                     &rparam, &rprcnt,                /* return params, length */
164                     &rdata, &rdrcnt))                /* return data, length */
165                 {
166                         int res = rparam? SVAL(rparam,0) : -1;
167
168                         if (res == 0 || res == ERRmoredata) {
169                                 int converter=SVAL(rparam,2);
170                                 int i;
171                                 char *rdata_end = rdata + rdrcnt;
172
173                                 count=SVAL(rparam,4);
174                                 p = rdata;
175
176                                 for (i=0;i<count;i++,p+=20) {
177                                         char *sname;
178                                         int type;
179                                         int comment_offset;
180                                         const char *cmnt;
181                                         const char *p1;
182                                         char *s1, *s2;
183                                         size_t len;
184                                         TALLOC_CTX *frame = talloc_stackframe();
185
186                                         if (p + 20 > rdata_end) {
187                                                 TALLOC_FREE(frame);
188                                                 break;
189                                         }
190
191                                         sname = p;
192                                         type = SVAL(p,14);
193                                         comment_offset = IVAL(p,16) & 0xFFFF;
194                                         if (comment_offset < 0 || comment_offset > (int)rdrcnt) {
195                                                 TALLOC_FREE(frame);
196                                                 break;
197                                         }
198                                         cmnt = comment_offset?(rdata+comment_offset-converter):"";
199
200                                         /* Work out the comment length. */
201                                         for (p1 = cmnt, len = 0; *p1 &&
202                                                         p1 < rdata_end; len++)
203                                                 p1++;
204                                         if (!*p1) {
205                                                 len++;
206                                         }
207                                         pull_string_talloc(frame,rdata,0,
208                                                 &s1,sname,14,STR_ASCII);
209                                         pull_string_talloc(frame,rdata,0,
210                                                 &s2,cmnt,len,STR_ASCII);
211                                         if (!s1 || !s2) {
212                                                 TALLOC_FREE(frame);
213                                                 continue;
214                                         }
215
216                                         fn(s1, type, s2, state);
217
218                                         TALLOC_FREE(frame);
219                                 }
220                         } else {
221                                 DEBUG(4,("NetShareEnum res=%d\n", res));
222                         }
223                 } else {
224                         DEBUG(4,("NetShareEnum failed\n"));
225                 }
226
227         SAFE_FREE(rparam);
228         SAFE_FREE(rdata);
229
230         return count;
231 }
232
233 /****************************************************************************
234  Call a NetServerEnum for the specified workgroup and servertype mask.  This
235  function then calls the specified callback function for each name returned.
236
237  The callback function takes 4 arguments: the machine name, the server type,
238  the comment and a state pointer.
239 ****************************************************************************/
240
241 bool cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
242                        void (*fn)(const char *, uint32, const char *, void *),
243                        void *state)
244 {
245         char *rparam = NULL;
246         char *rdata = NULL;
247         unsigned int rdrcnt,rprcnt;
248         char *p;
249         char param[1024];
250         int uLevel = 1;
251         int count = -1;
252         size_t len;
253
254         errno = 0; /* reset */
255
256         /* send a SMBtrans command with api NetServerEnum */
257         p = param;
258         SSVAL(p,0,0x68); /* api number */
259         p += 2;
260         strlcpy(p,"WrLehDz", sizeof(param)-PTR_DIFF(p,param));
261         p = skip_string(param,sizeof(param),p);
262
263         strlcpy(p,"B16BBDz", sizeof(param)-PTR_DIFF(p,param));
264
265         p = skip_string(param,sizeof(param),p);
266         SSVAL(p,0,uLevel);
267         SSVAL(p,2,CLI_BUFFER_SIZE);
268         p += 4;
269         SIVAL(p,0,stype);
270         p += 4;
271
272         len = push_ascii(p, workgroup, sizeof(param)-PTR_DIFF(p,param)-1,
273                         STR_TERMINATE|STR_UPPER);
274         if (len == (size_t)-1) {
275                 return false;
276         }
277         p += len;
278
279         if (cli_api(cli,
280                     param, PTR_DIFF(p,param), 8,        /* params, length, max */
281                     NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
282                     &rparam, &rprcnt,                   /* return params, return size */
283                     &rdata, &rdrcnt                     /* return data, return size */
284                    )) {
285                 int res = rparam? SVAL(rparam,0) : -1;
286                 char *rdata_end = rdata + rdrcnt;
287
288                 if (res == 0 || res == ERRmoredata ||
289                     (res != -1 && cli_errno(cli) == 0)) {
290                         int i;
291                         int converter=SVAL(rparam,2);
292
293                         count=SVAL(rparam,4);
294                         p = rdata;
295
296                         for (i = 0;i < count;i++, p += 26) {
297                                 char *sname;
298                                 int comment_offset;
299                                 const char *cmnt;
300                                 const char *p1;
301                                 char *s1, *s2;
302                                 TALLOC_CTX *frame = talloc_stackframe();
303
304                                 if (p + 26 > rdata_end) {
305                                         TALLOC_FREE(frame);
306                                         break;
307                                 }
308
309                                 sname = p;
310                                 comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
311                                 cmnt = comment_offset?(rdata+comment_offset):"";
312
313                                 if (comment_offset < 0 || comment_offset > (int)rdrcnt) {
314                                         TALLOC_FREE(frame);
315                                         continue;
316                                 }
317
318                                 /* Work out the comment length. */
319                                 for (p1 = cmnt, len = 0; *p1 &&
320                                                 p1 < rdata_end; len++)
321                                         p1++;
322                                 if (!*p1) {
323                                         len++;
324                                 }
325
326                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
327
328                                 pull_string_talloc(frame,rdata,0,
329                                         &s1,sname,16,STR_ASCII);
330                                 pull_string_talloc(frame,rdata,0,
331                                         &s2,cmnt,len,STR_ASCII);
332
333                                 if (!s1 || !s2) {
334                                         TALLOC_FREE(frame);
335                                         continue;
336                                 }
337
338                                 fn(s1, stype, s2, state);
339                                 TALLOC_FREE(frame);
340                         }
341                 }
342         }
343
344         SAFE_FREE(rparam);
345         SAFE_FREE(rdata);
346
347         if (count < 0) {
348             errno = cli_errno(cli);
349         } else {
350             if (!count) {
351                 /* this is a very special case, when the domain master for the
352                    work group isn't part of the work group itself, there is something
353                    wild going on */
354                 errno = ENOENT;
355             }
356         }
357
358         return(count > 0);
359 }
360
361 /****************************************************************************
362  Send a SamOEMChangePassword command.
363 ****************************************************************************/
364
365 bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
366                              const char *old_password)
367 {
368         char param[1024];
369         unsigned char data[532];
370         char *p = param;
371         unsigned char old_pw_hash[16];
372         unsigned char new_pw_hash[16];
373         unsigned int data_len;
374         unsigned int param_len = 0;
375         char *rparam = NULL;
376         char *rdata = NULL;
377         unsigned int rprcnt, rdrcnt;
378
379         if (strlen(user) >= sizeof(fstring)-1) {
380                 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
381                 return False;
382         }
383
384         SSVAL(p,0,214); /* SamOEMChangePassword command. */
385         p += 2;
386         strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param));
387         p = skip_string(param,sizeof(param),p);
388         strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param));
389         p = skip_string(param,sizeof(param),p);
390         strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param));
391         p = skip_string(param,sizeof(param),p);
392         SSVAL(p,0,532);
393         p += 2;
394
395         param_len = PTR_DIFF(p,param);
396
397         /*
398          * Get the Lanman hash of the old password, we
399          * use this as the key to make_oem_passwd_hash().
400          */
401         E_deshash(old_password, old_pw_hash);
402
403         encode_pw_buffer(data, new_password, STR_ASCII);
404
405 #ifdef DEBUG_PASSWORD
406         DEBUG(100,("make_oem_passwd_hash\n"));
407         dump_data(100, data, 516);
408 #endif
409         SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
410
411         /*
412          * Now place the old password hash in the data.
413          */
414         E_deshash(new_password, new_pw_hash);
415
416         E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
417
418         data_len = 532;
419
420         if (cli_send_trans(cli,SMBtrans,
421                     PIPE_LANMAN,                          /* name */
422                     0,0,                                  /* fid, flags */
423                     NULL,0,0,                             /* setup, length, max */
424                     param,param_len,2,                    /* param, length, max */
425                     (char *)data,data_len,0                       /* data, length, max */
426                    ) == False) {
427                 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
428                         user ));
429                 return False;
430         }
431
432         if (!cli_receive_trans(cli,SMBtrans,
433                        &rparam, &rprcnt,
434                        &rdata, &rdrcnt)) {
435                 DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
436                         user ));
437                 return False;
438         }
439
440         if (rparam) {
441                 cli->rap_error = SVAL(rparam,0);
442         }
443
444         SAFE_FREE(rparam);
445         SAFE_FREE(rdata);
446
447         return (cli->rap_error == 0);
448 }
449
450 /****************************************************************************
451  Send a qpathinfo call.
452 ****************************************************************************/
453
454 bool cli_qpathinfo(struct cli_state *cli,
455                         const char *fname,
456                         time_t *change_time,
457                         time_t *access_time,
458                         time_t *write_time,
459                         SMB_OFF_T *size,
460                         uint16 *mode)
461 {
462         unsigned int data_len = 0;
463         unsigned int param_len = 0;
464         unsigned int rparam_len, rdata_len;
465         uint16 setup = TRANSACT2_QPATHINFO;
466         char *param;
467         char *rparam=NULL, *rdata=NULL;
468         int count=8;
469         bool ret;
470         time_t (*date_fn)(struct cli_state *, const void *);
471         char *p;
472         size_t nlen = 2*(strlen(fname)+1);
473
474         param = SMB_MALLOC(6+nlen+2);
475         if (!param) {
476                 return false;
477         }
478         p = param;
479         memset(p, '\0', 6);
480         SSVAL(p, 0, SMB_INFO_STANDARD);
481         p += 6;
482         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
483         param_len = PTR_DIFF(p, param);
484
485         do {
486                 ret = (cli_send_trans(cli, SMBtrans2,
487                                       NULL,           /* Name */
488                                       -1, 0,          /* fid, flags */
489                                       &setup, 1, 0,   /* setup, length, max */
490                                       param, param_len, 10, /* param, length, max */
491                                       NULL, data_len, cli->max_xmit /* data, length, max */
492                                       ) &&
493                        cli_receive_trans(cli, SMBtrans2,
494                                          &rparam, &rparam_len,
495                                          &rdata, &rdata_len));
496                 if (!cli_is_dos_error(cli)) break;
497                 if (!ret) {
498                         /* we need to work around a Win95 bug - sometimes
499                            it gives ERRSRV/ERRerror temprarily */
500                         uint8 eclass;
501                         uint32 ecode;
502                         cli_dos_error(cli, &eclass, &ecode);
503                         if (eclass != ERRSRV || ecode != ERRerror) break;
504                         smb_msleep(100);
505                 }
506         } while (count-- && ret==False);
507
508         SAFE_FREE(param);
509         if (!ret || !rdata || rdata_len < 22) {
510                 return False;
511         }
512
513         if (cli->win95) {
514                 date_fn = cli_make_unix_date;
515         } else {
516                 date_fn = cli_make_unix_date2;
517         }
518
519         if (change_time) {
520                 *change_time = date_fn(cli, rdata+0);
521         }
522         if (access_time) {
523                 *access_time = date_fn(cli, rdata+4);
524         }
525         if (write_time) {
526                 *write_time = date_fn(cli, rdata+8);
527         }
528         if (size) {
529                 *size = IVAL(rdata, 12);
530         }
531         if (mode) {
532                 *mode = SVAL(rdata,l1_attrFile);
533         }
534
535         SAFE_FREE(rdata);
536         SAFE_FREE(rparam);
537         return True;
538 }
539
540 /****************************************************************************
541  Send a setpathinfo call.
542 ****************************************************************************/
543
544 bool cli_setpathinfo(struct cli_state *cli, const char *fname,
545                      time_t create_time,
546                      time_t access_time,
547                      time_t write_time,
548                      time_t change_time,
549                      uint16 mode)
550 {
551         unsigned int data_len = 0;
552         unsigned int param_len = 0;
553         unsigned int rparam_len, rdata_len;
554         uint16 setup = TRANSACT2_SETPATHINFO;
555         char *param;
556         char data[40];
557         char *rparam=NULL, *rdata=NULL;
558         int count=8;
559         bool ret;
560         char *p;
561         size_t nlen = 2*(strlen(fname)+1);
562
563         param = SMB_MALLOC(6+nlen+2);
564         if (!param) {
565                 return false;
566         }
567         memset(param, '\0', 6);
568         memset(data, 0, sizeof(data));
569
570         p = param;
571
572         /* Add the information level */
573         SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
574
575         /* Skip reserved */
576         p += 6;
577
578         /* Add the file name */
579         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
580
581         param_len = PTR_DIFF(p, param);
582
583         p = data;
584
585         /*
586          * Add the create, last access, modification, and status change times
587          */
588         put_long_date(p, create_time);
589         p += 8;
590
591         put_long_date(p, access_time);
592         p += 8;
593
594         put_long_date(p, write_time);
595         p += 8;
596
597         put_long_date(p, change_time);
598         p += 8;
599
600         /* Add attributes */
601         SIVAL(p, 0, mode);
602         p += 4;
603
604         /* Add padding */
605         SIVAL(p, 0, 0);
606         p += 4;
607
608         data_len = PTR_DIFF(p, data);
609
610         do {
611                 ret = (cli_send_trans(cli, SMBtrans2,
612                                       NULL,           /* Name */
613                                       -1, 0,          /* fid, flags */
614                                       &setup, 1, 0,   /* setup, length, max */
615                                       param, param_len, 10, /* param, length, max */
616                                       data, data_len, cli->max_xmit /* data, length, max */
617                                       ) &&
618                        cli_receive_trans(cli, SMBtrans2,
619                                          &rparam, &rparam_len,
620                                          &rdata, &rdata_len));
621                 if (!cli_is_dos_error(cli)) break;
622                 if (!ret) {
623                         /* we need to work around a Win95 bug - sometimes
624                            it gives ERRSRV/ERRerror temprarily */
625                         uint8 eclass;
626                         uint32 ecode;
627                         cli_dos_error(cli, &eclass, &ecode);
628                         if (eclass != ERRSRV || ecode != ERRerror) break;
629                         smb_msleep(100);
630                 }
631         } while (count-- && ret==False);
632
633         SAFE_FREE(param);
634         if (!ret) {
635                 return False;
636         }
637
638         SAFE_FREE(rdata);
639         SAFE_FREE(rparam);
640         return True;
641 }
642
643 /****************************************************************************
644  Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
645 ****************************************************************************/
646
647 bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
648                     struct timespec *create_time,
649                     struct timespec *access_time,
650                     struct timespec *write_time,
651                     struct timespec *change_time,
652                     SMB_OFF_T *size, uint16 *mode,
653                     SMB_INO_T *ino)
654 {
655         unsigned int data_len = 0;
656         unsigned int param_len = 0;
657         uint16 setup = TRANSACT2_QPATHINFO;
658         char *param;
659         char *rparam=NULL, *rdata=NULL;
660         char *p;
661         size_t nlen = 2*(strlen(fname)+1);
662
663         param = SMB_MALLOC(6+nlen+2);
664         if (!param) {
665                 return false;
666         }
667         p = param;
668         memset(param, '\0', 6);
669         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
670         p += 6;
671         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
672
673         param_len = PTR_DIFF(p, param);
674
675         if (!cli_send_trans(cli, SMBtrans2,
676                             NULL,                         /* name */
677                             -1, 0,                        /* fid, flags */
678                             &setup, 1, 0,                 /* setup, length, max */
679                             param, param_len, 10,         /* param, length, max */
680                             NULL, data_len, cli->max_xmit /* data, length, max */
681                            )) {
682                 SAFE_FREE(param);
683                 return False;
684         }
685
686         SAFE_FREE(param);
687         if (!cli_receive_trans(cli, SMBtrans2,
688                                &rparam, &param_len,
689                                &rdata, &data_len)) {
690                 return False;
691         }
692
693         if (!rdata || data_len < 22) {
694                 return False;
695         }
696
697         if (create_time) {
698                 *create_time = interpret_long_date(rdata+0);
699         }
700         if (access_time) {
701                 *access_time = interpret_long_date(rdata+8);
702         }
703         if (write_time) {
704                 *write_time = interpret_long_date(rdata+16);
705         }
706         if (change_time) {
707                 *change_time = interpret_long_date(rdata+24);
708         }
709         if (mode) {
710                 *mode = SVAL(rdata, 32);
711         }
712         if (size) {
713                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
714         }
715         if (ino) {
716                 *ino = IVAL(rdata, 64);
717         }
718
719         SAFE_FREE(rdata);
720         SAFE_FREE(rparam);
721         return True;
722 }
723
724 /****************************************************************************
725  Send a qfileinfo QUERY_FILE_NAME_INFO call.
726 ****************************************************************************/
727
728 bool cli_qfilename(struct cli_state *cli, int fnum, char *name, size_t namelen)
729 {
730         unsigned int data_len = 0;
731         unsigned int param_len = 0;
732         uint16 setup = TRANSACT2_QFILEINFO;
733         char param[4];
734         char *rparam=NULL, *rdata=NULL;
735
736         param_len = 4;
737         SSVAL(param, 0, fnum);
738         SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
739
740         if (!cli_send_trans(cli, SMBtrans2,
741                             NULL,                         /* name */
742                             -1, 0,                        /* fid, flags */
743                             &setup, 1, 0,                 /* setup, length, max */
744                             param, param_len, 2,          /* param, length, max */
745                             NULL, data_len, cli->max_xmit /* data, length, max */
746                            )) {
747                 return False;
748         }
749
750         if (!cli_receive_trans(cli, SMBtrans2,
751                                &rparam, &param_len,
752                                &rdata, &data_len)) {
753                 return False;
754         }
755
756         if (!rdata || data_len < 4) {
757                 return False;
758         }
759
760         clistr_pull(cli, name, rdata+4, namelen, IVAL(rdata, 0), STR_UNICODE);
761
762         return True;
763 }
764
765 /****************************************************************************
766  Send a qfileinfo call.
767 ****************************************************************************/
768
769 bool cli_qfileinfo(struct cli_state *cli, int fnum,
770                    uint16 *mode, SMB_OFF_T *size,
771                    struct timespec *create_time,
772                    struct timespec *access_time,
773                    struct timespec *write_time,
774                    struct timespec *change_time,
775                    SMB_INO_T *ino)
776 {
777         unsigned int data_len = 0;
778         unsigned int param_len = 0;
779         uint16 setup = TRANSACT2_QFILEINFO;
780         char param[4];
781         char *rparam=NULL, *rdata=NULL;
782
783         /* if its a win95 server then fail this - win95 totally screws it
784            up */
785         if (cli->win95) return False;
786
787         param_len = 4;
788
789         SSVAL(param, 0, fnum);
790         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
791
792         if (!cli_send_trans(cli, SMBtrans2,
793                             NULL,                         /* name */
794                             -1, 0,                        /* fid, flags */
795                             &setup, 1, 0,                 /* setup, length, max */
796                             param, param_len, 2,          /* param, length, max */
797                             NULL, data_len, cli->max_xmit /* data, length, max */
798                            )) {
799                 return False;
800         }
801
802         if (!cli_receive_trans(cli, SMBtrans2,
803                                &rparam, &param_len,
804                                &rdata, &data_len)) {
805                 return False;
806         }
807
808         if (!rdata || data_len < 68) {
809                 return False;
810         }
811
812         if (create_time) {
813                 *create_time = interpret_long_date(rdata+0);
814         }
815         if (access_time) {
816                 *access_time = interpret_long_date(rdata+8);
817         }
818         if (write_time) {
819                 *write_time = interpret_long_date(rdata+16);
820         }
821         if (change_time) {
822                 *change_time = interpret_long_date(rdata+24);
823         }
824         if (mode) {
825                 *mode = SVAL(rdata, 32);
826         }
827         if (size) {
828                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
829         }
830         if (ino) {
831                 *ino = IVAL(rdata, 64);
832         }
833
834         SAFE_FREE(rdata);
835         SAFE_FREE(rparam);
836         return True;
837 }
838
839 /****************************************************************************
840  Send a qpathinfo BASIC_INFO call.
841 ****************************************************************************/
842
843 bool cli_qpathinfo_basic( struct cli_state *cli, const char *name,
844                           SMB_STRUCT_STAT *sbuf, uint32 *attributes )
845 {
846         unsigned int param_len = 0;
847         unsigned int data_len = 0;
848         uint16 setup = TRANSACT2_QPATHINFO;
849         char *param;
850         char *rparam=NULL, *rdata=NULL;
851         char *p;
852         char *path;
853         int len;
854         size_t nlen;
855         TALLOC_CTX *frame = talloc_stackframe();
856
857         path = talloc_strdup(frame, name);
858         if (!path) {
859                 TALLOC_FREE(frame);
860                 return false;
861         }
862         /* cleanup */
863
864         len = strlen(path);
865         if ( path[len-1] == '\\' || path[len-1] == '/') {
866                 path[len-1] = '\0';
867         }
868         nlen = 2*(strlen(path)+1);
869
870         param = TALLOC_ARRAY(frame,char,6+nlen+2);
871         if (!param) {
872                 return false;
873         }
874         p = param;
875         memset(param, '\0', 6);
876
877         SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
878         p += 6;
879         p += clistr_push(cli, p, path, nlen, STR_TERMINATE);
880         param_len = PTR_DIFF(p, param);
881
882
883         if (!cli_send_trans(cli, SMBtrans2,
884                         NULL,                        /* name */
885                         -1, 0,                       /* fid, flags */
886                         &setup, 1, 0,                /* setup, length, max */
887                         param, param_len, 2,         /* param, length, max */
888                         NULL,  0, cli->max_xmit      /* data, length, max */
889                         )) {
890                 TALLOC_FREE(frame);
891                 return False;
892         }
893
894         TALLOC_FREE(frame);
895
896         if (!cli_receive_trans(cli, SMBtrans2,
897                 &rparam, &param_len,
898                 &rdata, &data_len)) {
899                         return False;
900         }
901
902         if (data_len < 36) {
903                 SAFE_FREE(rdata);
904                 SAFE_FREE(rparam);
905                 return False;
906         }
907
908         set_atimespec(sbuf, interpret_long_date( rdata+8 )); /* Access time. */
909         set_mtimespec(sbuf, interpret_long_date( rdata+16 )); /* Write time. */
910         set_ctimespec(sbuf, interpret_long_date( rdata+24 )); /* Change time. */
911
912         *attributes = IVAL( rdata, 32 );
913
914         SAFE_FREE(rparam);
915         SAFE_FREE(rdata);
916
917         return True;
918 }
919
920 /****************************************************************************
921  Send a qfileinfo call.
922 ****************************************************************************/
923
924 bool cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
925 {
926         unsigned int data_len = 0;
927         unsigned int param_len = 0;
928         uint16 setup = TRANSACT2_QFILEINFO;
929         char param[4];
930         char *rparam=NULL, *rdata=NULL;
931
932         *poutdata = NULL;
933         *poutlen = 0;
934
935         /* if its a win95 server then fail this - win95 totally screws it
936            up */
937         if (cli->win95)
938                 return False;
939
940         param_len = 4;
941
942         SSVAL(param, 0, fnum);
943         SSVAL(param, 2, level);
944
945         if (!cli_send_trans(cli, SMBtrans2,
946                             NULL,                           /* name */
947                             -1, 0,                          /* fid, flags */
948                             &setup, 1, 0,                   /* setup, length, max */
949                             param, param_len, 2,            /* param, length, max */
950                             NULL, data_len, cli->max_xmit   /* data, length, max */
951                            )) {
952                 return False;
953         }
954
955         if (!cli_receive_trans(cli, SMBtrans2,
956                                &rparam, &param_len,
957                                &rdata, &data_len)) {
958                 return False;
959         }
960
961         *poutdata = (char *)memdup(rdata, data_len);
962         if (!*poutdata) {
963                 SAFE_FREE(rdata);
964                 SAFE_FREE(rparam);
965                 return False;
966         }
967
968         *poutlen = data_len;
969
970         SAFE_FREE(rdata);
971         SAFE_FREE(rparam);
972         return True;
973 }
974
975 /****************************************************************************
976  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
977 ****************************************************************************/
978
979 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
980 {
981         unsigned int data_len = 0;
982         unsigned int param_len = 0;
983         uint16 setup = TRANSACT2_QPATHINFO;
984         char *param;
985         char *rparam=NULL, *rdata=NULL;
986         int count=8;
987         char *p;
988         bool ret;
989         unsigned int len;
990         size_t nlen = 2*(strlen(fname)+1);
991
992         param = SMB_MALLOC(6+nlen+2);
993         if (!param) {
994                 return NT_STATUS_NO_MEMORY;
995         }
996         p = param;
997         memset(param, '\0', 6);
998         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
999         p += 6;
1000         p += clistr_push(cli, p, fname, nlen, STR_TERMINATE);
1001         param_len = PTR_DIFF(p, param);
1002
1003         do {
1004                 ret = (cli_send_trans(cli, SMBtrans2,
1005                                       NULL,           /* Name */
1006                                       -1, 0,          /* fid, flags */
1007                                       &setup, 1, 0,   /* setup, length, max */
1008                                       param, param_len, 10, /* param, length, max */
1009                                       NULL, data_len, cli->max_xmit /* data, length, max */
1010                                       ) &&
1011                        cli_receive_trans(cli, SMBtrans2,
1012                                          &rparam, &param_len,
1013                                          &rdata, &data_len));
1014                 if (!ret && cli_is_dos_error(cli)) {
1015                         /* we need to work around a Win95 bug - sometimes
1016                            it gives ERRSRV/ERRerror temprarily */
1017                         uint8 eclass;
1018                         uint32 ecode;
1019                         cli_dos_error(cli, &eclass, &ecode);
1020                         if (eclass != ERRSRV || ecode != ERRerror) break;
1021                         smb_msleep(100);
1022                 }
1023         } while (count-- && ret==False);
1024
1025         SAFE_FREE(param);
1026
1027         if (!ret || !rdata || data_len < 4) {
1028                 return NT_STATUS_UNSUCCESSFUL;
1029         }
1030
1031         len = IVAL(rdata, 0);
1032
1033         if (len > data_len - 4) {
1034                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1035         }
1036
1037         clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
1038
1039         SAFE_FREE(rdata);
1040         SAFE_FREE(rparam);
1041
1042         return NT_STATUS_OK;
1043 }