r23779: Change from v2 or later to v3 or later.
[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    
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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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         pstring param;
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         pstrcpy_base(p,"OOWb54WrLh",param);
89         p = skip_string(param,sizeof(param),p);
90         pstrcpy_base(p,"WB21BWDWWDDDDDDDzzzD",param);
91         p = skip_string(param,sizeof(param),p);
92         SSVAL(p,0,1);
93         p += 2;
94         pstrcpy_base(p,user,param);
95         strupper_m(p);
96         p += 21;
97         p++;
98         p += 15;
99         p++; 
100         pstrcpy_base(p, workstation, 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         pstring param;
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         pstrcpy_base(p,"WrLeh",param);
150         p = skip_string(param,sizeof(param),p);
151         pstrcpy_base(p,"B13BWz",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                                 
173                                 count=SVAL(rparam,4);
174                                 p = rdata;
175                                 
176                                 for (i=0;i<count;i++,p+=20) {
177                                         char *sname = p;
178                                         int type = SVAL(p,14);
179                                         int comment_offset = IVAL(p,16) & 0xFFFF;
180                                         const char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
181                                         pstring s1, s2;
182
183                                         pull_ascii_pstring(s1, sname);
184                                         pull_ascii_pstring(s2, cmnt);
185
186                                         fn(s1, type, s2, state);
187                                 }
188                         } else {
189                                 DEBUG(4,("NetShareEnum res=%d\n", res));
190                         }      
191                 } else {
192                         DEBUG(4,("NetShareEnum failed\n"));
193                 }
194   
195         SAFE_FREE(rparam);
196         SAFE_FREE(rdata);
197         
198         return count;
199 }
200
201 /****************************************************************************
202  Call a NetServerEnum for the specified workgroup and servertype mask.  This
203  function then calls the specified callback function for each name returned.
204
205  The callback function takes 4 arguments: the machine name, the server type,
206  the comment and a state pointer.
207 ****************************************************************************/
208
209 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
210                        void (*fn)(const char *, uint32, const char *, void *),
211                        void *state)
212 {
213         char *rparam = NULL;
214         char *rdata = NULL;
215         unsigned int rdrcnt,rprcnt;
216         char *p;
217         pstring param;
218         int uLevel = 1;
219         int count = -1;
220
221         errno = 0; /* reset */
222
223         /* send a SMBtrans command with api NetServerEnum */
224         p = param;
225         SSVAL(p,0,0x68); /* api number */
226         p += 2;
227         pstrcpy_base(p,"WrLehDz", param);
228         p = skip_string(param,sizeof(param),p);
229   
230         pstrcpy_base(p,"B16BBDz", param);
231
232         p = skip_string(param,sizeof(param),p);
233         SSVAL(p,0,uLevel);
234         SSVAL(p,2,CLI_BUFFER_SIZE);
235         p += 4;
236         SIVAL(p,0,stype);
237         p += 4;
238
239         p += push_ascii(p, workgroup, sizeof(pstring)-PTR_DIFF(p,param)-1, STR_TERMINATE|STR_UPPER);
240         
241         if (cli_api(cli, 
242                     param, PTR_DIFF(p,param), 8,        /* params, length, max */
243                     NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
244                     &rparam, &rprcnt,                   /* return params, return size */
245                     &rdata, &rdrcnt                     /* return data, return size */
246                    )) {
247                 int res = rparam? SVAL(rparam,0) : -1;
248                         
249                 if (res == 0 || res == ERRmoredata ||
250                     (res != -1 && cli_errno(cli) == 0)) {
251                         int i;
252                         int converter=SVAL(rparam,2);
253
254                         count=SVAL(rparam,4);
255                         p = rdata;
256                                         
257                         for (i = 0;i < count;i++, p += 26) {
258                                 char *sname = p;
259                                 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
260                                 const char *cmnt = comment_offset?(rdata+comment_offset):"";
261                                 pstring s1, s2;
262
263                                 if (comment_offset < 0 || comment_offset > (int)rdrcnt) continue;
264
265                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
266
267                                 pull_ascii_pstring(s1, sname);
268                                 pull_ascii_pstring(s2, cmnt);
269                                 fn(s1, stype, s2, state);
270                         }
271                 }
272         }
273   
274         SAFE_FREE(rparam);
275         SAFE_FREE(rdata);
276
277         if (count < 0) {
278             errno = cli_errno(cli);
279         } else {
280             if (!count) {
281                 /* this is a very special case, when the domain master for the 
282                    work group isn't part of the work group itself, there is something
283                    wild going on */
284                 errno = ENOENT;
285             }
286         }
287                         
288         return(count > 0);
289 }
290
291 /****************************************************************************
292  Send a SamOEMChangePassword command.
293 ****************************************************************************/
294
295 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
296                              const char *old_password)
297 {
298         pstring param;
299         unsigned char data[532];
300         char *p = param;
301         unsigned char old_pw_hash[16];
302         unsigned char new_pw_hash[16];
303         unsigned int data_len;
304         unsigned int param_len = 0;
305         char *rparam = NULL;
306         char *rdata = NULL;
307         unsigned int rprcnt, rdrcnt;
308
309         if (strlen(user) >= sizeof(fstring)-1) {
310                 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
311                 return False;
312         }
313
314         SSVAL(p,0,214); /* SamOEMChangePassword command. */
315         p += 2;
316         pstrcpy_base(p, "zsT", param);
317         p = skip_string(param,sizeof(param),p);
318         pstrcpy_base(p, "B516B16", param);
319         p = skip_string(param,sizeof(param),p);
320         pstrcpy_base(p,user, param);
321         p = skip_string(param,sizeof(param),p);
322         SSVAL(p,0,532);
323         p += 2;
324
325         param_len = PTR_DIFF(p,param);
326
327         /*
328          * Get the Lanman hash of the old password, we
329          * use this as the key to make_oem_passwd_hash().
330          */
331         E_deshash(old_password, old_pw_hash);
332
333         encode_pw_buffer(data, new_password, STR_ASCII);
334   
335 #ifdef DEBUG_PASSWORD
336         DEBUG(100,("make_oem_passwd_hash\n"));
337         dump_data(100, data, 516);
338 #endif
339         SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
340
341         /* 
342          * Now place the old password hash in the data.
343          */
344         E_deshash(new_password, new_pw_hash);
345
346         E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
347
348         data_len = 532;
349     
350         if (cli_send_trans(cli,SMBtrans,
351                     PIPE_LANMAN,                          /* name */
352                     0,0,                                  /* fid, flags */
353                     NULL,0,0,                             /* setup, length, max */
354                     param,param_len,2,                    /* param, length, max */
355                     (char *)data,data_len,0                       /* data, length, max */
356                    ) == False) {
357                 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
358                         user ));
359                 return False;
360         }
361
362         if (!cli_receive_trans(cli,SMBtrans,
363                        &rparam, &rprcnt,
364                        &rdata, &rdrcnt)) {
365                 DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
366                         user ));
367                 return False;
368         }
369   
370         if (rparam) {
371                 cli->rap_error = SVAL(rparam,0);
372         }
373   
374         SAFE_FREE(rparam);
375         SAFE_FREE(rdata);
376
377         return (cli->rap_error == 0);
378 }
379
380 /****************************************************************************
381  Send a qpathinfo call.
382 ****************************************************************************/
383
384 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
385                    time_t *change_time,
386                    time_t *access_time,
387                    time_t *write_time, 
388                    SMB_OFF_T *size, uint16 *mode)
389 {
390         unsigned int data_len = 0;
391         unsigned int param_len = 0;
392         unsigned int rparam_len, rdata_len;
393         uint16 setup = TRANSACT2_QPATHINFO;
394         pstring param;
395         char *rparam=NULL, *rdata=NULL;
396         int count=8;
397         BOOL ret;
398         time_t (*date_fn)(struct cli_state *, void *);
399         char *p;
400
401         p = param;
402         memset(p, 0, 6);
403         SSVAL(p, 0, SMB_INFO_STANDARD);
404         p += 6;
405         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
406
407         param_len = PTR_DIFF(p, param);
408
409         do {
410                 ret = (cli_send_trans(cli, SMBtrans2, 
411                                       NULL,           /* Name */
412                                       -1, 0,          /* fid, flags */
413                                       &setup, 1, 0,   /* setup, length, max */
414                                       param, param_len, 10, /* param, length, max */
415                                       NULL, data_len, cli->max_xmit /* data, length, max */
416                                       ) &&
417                        cli_receive_trans(cli, SMBtrans2, 
418                                          &rparam, &rparam_len,
419                                          &rdata, &rdata_len));
420                 if (!cli_is_dos_error(cli)) break;
421                 if (!ret) {
422                         /* we need to work around a Win95 bug - sometimes
423                            it gives ERRSRV/ERRerror temprarily */
424                         uint8 eclass;
425                         uint32 ecode;
426                         cli_dos_error(cli, &eclass, &ecode);
427                         if (eclass != ERRSRV || ecode != ERRerror) break;
428                         smb_msleep(100);
429                 }
430         } while (count-- && ret==False);
431
432         if (!ret || !rdata || rdata_len < 22) {
433                 return False;
434         }
435
436         if (cli->win95) {
437                 date_fn = cli_make_unix_date;
438         } else {
439                 date_fn = cli_make_unix_date2;
440         }
441
442         if (change_time) {
443                 *change_time = date_fn(cli, rdata+0);
444         }
445         if (access_time) {
446                 *access_time = date_fn(cli, rdata+4);
447         }
448         if (write_time) {
449                 *write_time = date_fn(cli, rdata+8);
450         }
451         if (size) {
452                 *size = IVAL(rdata, 12);
453         }
454         if (mode) {
455                 *mode = SVAL(rdata,l1_attrFile);
456         }
457
458         SAFE_FREE(rdata);
459         SAFE_FREE(rparam);
460         return True;
461 }
462
463 /****************************************************************************
464  Send a setpathinfo call.
465 ****************************************************************************/
466
467 BOOL cli_setpathinfo(struct cli_state *cli, const char *fname, 
468                      time_t create_time,
469                      time_t access_time,
470                      time_t write_time,
471                      time_t change_time,
472                      uint16 mode)
473 {
474         unsigned int data_len = 0;
475         unsigned int param_len = 0;
476         unsigned int rparam_len, rdata_len;
477         uint16 setup = TRANSACT2_SETPATHINFO;
478         pstring param;
479         pstring data;
480         char *rparam=NULL, *rdata=NULL;
481         int count=8;
482         BOOL ret;
483         char *p;
484
485         memset(param, 0, sizeof(param));
486         memset(data, 0, sizeof(data));
487
488         p = param;
489
490         /* Add the information level */
491         SSVAL(p, 0, SMB_FILE_BASIC_INFORMATION);
492
493         /* Skip reserved */
494         p += 6;
495
496         /* Add the file name */
497         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
498
499         param_len = PTR_DIFF(p, param);
500
501         p = data;
502
503         /*
504          * Add the create, last access, modification, and status change times
505          */
506         
507         put_long_date(p, create_time);
508         p += 8;
509
510         put_long_date(p, access_time);
511         p += 8;
512         
513         put_long_date(p, write_time);
514         p += 8;
515         
516         put_long_date(p, change_time);
517         p += 8;
518
519         /* Add attributes */
520         SIVAL(p, 0, mode);
521         p += 4;
522
523         /* Add padding */
524         SIVAL(p, 0, 0);
525         p += 4;
526
527         data_len = PTR_DIFF(p, data);
528
529         do {
530                 ret = (cli_send_trans(cli, SMBtrans2, 
531                                       NULL,           /* Name */
532                                       -1, 0,          /* fid, flags */
533                                       &setup, 1, 0,   /* setup, length, max */
534                                       param, param_len, 10, /* param, length, max */
535                                       data, data_len, cli->max_xmit /* data, length, max */
536                                       ) &&
537                        cli_receive_trans(cli, SMBtrans2, 
538                                          &rparam, &rparam_len,
539                                          &rdata, &rdata_len));
540                 if (!cli_is_dos_error(cli)) break;
541                 if (!ret) {
542                         /* we need to work around a Win95 bug - sometimes
543                            it gives ERRSRV/ERRerror temprarily */
544                         uint8 eclass;
545                         uint32 ecode;
546                         cli_dos_error(cli, &eclass, &ecode);
547                         if (eclass != ERRSRV || ecode != ERRerror) break;
548                         smb_msleep(100);
549                 }
550         } while (count-- && ret==False);
551
552         if (!ret) {
553                 return False;
554         }
555
556         SAFE_FREE(rdata);
557         SAFE_FREE(rparam);
558         return True;
559 }
560
561 /****************************************************************************
562  Send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level.
563 ****************************************************************************/
564
565 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, 
566                     struct timespec *create_time,
567                     struct timespec *access_time,
568                     struct timespec *write_time, 
569                     struct timespec *change_time,
570                     SMB_OFF_T *size, uint16 *mode,
571                     SMB_INO_T *ino)
572 {
573         unsigned int data_len = 0;
574         unsigned int param_len = 0;
575         uint16 setup = TRANSACT2_QPATHINFO;
576         pstring param;
577         char *rparam=NULL, *rdata=NULL;
578         char *p;
579
580         p = param;
581         memset(p, 0, 6);
582         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
583         p += 6;
584         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
585
586         param_len = PTR_DIFF(p, param);
587
588         if (!cli_send_trans(cli, SMBtrans2, 
589                             NULL,                         /* name */
590                             -1, 0,                        /* fid, flags */
591                             &setup, 1, 0,                 /* setup, length, max */
592                             param, param_len, 10,         /* param, length, max */
593                             NULL, data_len, cli->max_xmit /* data, length, max */
594                            )) {
595                 return False;
596         }
597
598         if (!cli_receive_trans(cli, SMBtrans2,
599                                &rparam, &param_len,
600                                &rdata, &data_len)) {
601                 return False;
602         }
603
604         if (!rdata || data_len < 22) {
605                 return False;
606         }
607         
608         if (create_time) {
609                 *create_time = interpret_long_date(rdata+0);
610         }
611         if (access_time) {
612                 *access_time = interpret_long_date(rdata+8);
613         }
614         if (write_time) {
615                 *write_time = interpret_long_date(rdata+16);
616         }
617         if (change_time) {
618                 *change_time = interpret_long_date(rdata+24);
619         }
620         if (mode) {
621                 *mode = SVAL(rdata, 32);
622         }
623         if (size) {
624                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
625         }
626         if (ino) {
627                 *ino = IVAL(rdata, 64);
628         }
629
630         SAFE_FREE(rdata);
631         SAFE_FREE(rparam);
632         return True;
633 }
634
635 /****************************************************************************
636  Send a qfileinfo QUERY_FILE_NAME_INFO call.
637 ****************************************************************************/
638
639 BOOL cli_qfilename(struct cli_state *cli, int fnum, 
640                    pstring name)
641 {
642         unsigned int data_len = 0;
643         unsigned int param_len = 0;
644         uint16 setup = TRANSACT2_QFILEINFO;
645         pstring param;
646         char *rparam=NULL, *rdata=NULL;
647
648         param_len = 4;
649         memset(param, 0, param_len);
650         SSVAL(param, 0, fnum);
651         SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
652
653         if (!cli_send_trans(cli, SMBtrans2, 
654                             NULL,                         /* name */
655                             -1, 0,                        /* fid, flags */
656                             &setup, 1, 0,                 /* setup, length, max */
657                             param, param_len, 2,          /* param, length, max */
658                             NULL, data_len, cli->max_xmit /* data, length, max */
659                            )) {
660                 return False;
661         }
662
663         if (!cli_receive_trans(cli, SMBtrans2,
664                                &rparam, &param_len,
665                                &rdata, &data_len)) {
666                 return False;
667         }
668
669         if (!rdata || data_len < 4) {
670                 return False;
671         }
672
673         clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE);
674
675         return True;
676 }
677
678 /****************************************************************************
679  Send a qfileinfo call.
680 ****************************************************************************/
681
682 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
683                    uint16 *mode, SMB_OFF_T *size,
684                    struct timespec *create_time,
685                    struct timespec *access_time,
686                    struct timespec *write_time, 
687                    struct timespec *change_time,
688                    SMB_INO_T *ino)
689 {
690         unsigned int data_len = 0;
691         unsigned int param_len = 0;
692         uint16 setup = TRANSACT2_QFILEINFO;
693         pstring param;
694         char *rparam=NULL, *rdata=NULL;
695
696         /* if its a win95 server then fail this - win95 totally screws it
697            up */
698         if (cli->win95) return False;
699
700         param_len = 4;
701
702         memset(param, 0, param_len);
703         SSVAL(param, 0, fnum);
704         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
705
706         if (!cli_send_trans(cli, SMBtrans2, 
707                             NULL,                         /* name */
708                             -1, 0,                        /* fid, flags */
709                             &setup, 1, 0,                 /* setup, length, max */
710                             param, param_len, 2,          /* param, length, max */
711                             NULL, data_len, cli->max_xmit /* data, length, max */
712                            )) {
713                 return False;
714         }
715
716         if (!cli_receive_trans(cli, SMBtrans2,
717                                &rparam, &param_len,
718                                &rdata, &data_len)) {
719                 return False;
720         }
721
722         if (!rdata || data_len < 68) {
723                 return False;
724         }
725
726         if (create_time) {
727                 *create_time = interpret_long_date(rdata+0);
728         }
729         if (access_time) {
730                 *access_time = interpret_long_date(rdata+8);
731         }
732         if (write_time) {
733                 *write_time = interpret_long_date(rdata+16);
734         }
735         if (change_time) {
736                 *change_time = interpret_long_date(rdata+24);
737         }
738         if (mode) {
739                 *mode = SVAL(rdata, 32);
740         }
741         if (size) {
742                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
743         }
744         if (ino) {
745                 *ino = IVAL(rdata, 64);
746         }
747
748         SAFE_FREE(rdata);
749         SAFE_FREE(rparam);
750         return True;
751 }
752
753 /****************************************************************************
754  Send a qpathinfo BASIC_INFO call.
755 ****************************************************************************/
756
757 BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name, 
758                           SMB_STRUCT_STAT *sbuf, uint32 *attributes )
759 {
760         unsigned int param_len = 0;
761         unsigned int data_len = 0;
762         uint16 setup = TRANSACT2_QPATHINFO;
763         char param[sizeof(pstring)+6];
764         char *rparam=NULL, *rdata=NULL;
765         char *p;
766         pstring path;
767         int len;
768         
769         pstrcpy( path, name );
770         /* cleanup */
771         
772         len = strlen( path );
773         if ( path[len-1] == '\\' || path[len-1] == '/')
774                 path[len-1] = '\0';
775
776         p = param;
777         memset(p, 0, 6);
778         SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
779         p += 6;
780         p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
781         param_len = PTR_DIFF(p, param);
782
783         if (!cli_send_trans(cli, SMBtrans2,
784                 NULL,                        /* name */
785                 -1, 0,                       /* fid, flags */
786                 &setup, 1, 0,                /* setup, length, max */
787                 param, param_len, 2,         /* param, length, max */
788                 NULL,  0, cli->max_xmit      /* data, length, max */
789                 )) {
790                         return False;
791         }
792
793         if (!cli_receive_trans(cli, SMBtrans2,
794                 &rparam, &param_len,
795                 &rdata, &data_len)) {
796                         return False;
797         }
798
799         if (data_len < 36) {
800                 SAFE_FREE(rdata);
801                 SAFE_FREE(rparam);
802                 return False;
803         }
804
805         set_atimespec(sbuf, interpret_long_date( rdata+8 )); /* Access time. */
806         set_mtimespec(sbuf, interpret_long_date( rdata+16 )); /* Write time. */
807         set_ctimespec(sbuf, interpret_long_date( rdata+24 )); /* Change time. */
808         
809         *attributes = IVAL( rdata, 32 );
810         
811         SAFE_FREE(rparam);
812         SAFE_FREE(rdata);
813         
814         return True;
815 }
816
817 /****************************************************************************
818  Send a qfileinfo call.
819 ****************************************************************************/
820
821 BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
822 {
823         unsigned int data_len = 0;
824         unsigned int param_len = 0;
825         uint16 setup = TRANSACT2_QFILEINFO;
826         pstring param;
827         char *rparam=NULL, *rdata=NULL;
828
829         *poutdata = NULL;
830         *poutlen = 0;
831
832         /* if its a win95 server then fail this - win95 totally screws it
833            up */
834         if (cli->win95)
835                 return False;
836
837         param_len = 4;
838
839         memset(param, 0, param_len);
840         SSVAL(param, 0, fnum);
841         SSVAL(param, 2, level);
842
843         if (!cli_send_trans(cli, SMBtrans2, 
844                             NULL,                           /* name */
845                             -1, 0,                          /* fid, flags */
846                             &setup, 1, 0,                   /* setup, length, max */
847                             param, param_len, 2,            /* param, length, max */
848                             NULL, data_len, cli->max_xmit   /* data, length, max */
849                            )) {
850                 return False;
851         }
852
853         if (!cli_receive_trans(cli, SMBtrans2,
854                                &rparam, &param_len,
855                                &rdata, &data_len)) {
856                 return False;
857         }
858
859         *poutdata = (char *)memdup(rdata, data_len);
860         if (!*poutdata) {
861                 SAFE_FREE(rdata);
862                 SAFE_FREE(rparam);
863                 return False;
864         }
865
866         *poutlen = data_len;
867
868         SAFE_FREE(rdata);
869         SAFE_FREE(rparam);
870         return True;
871 }
872
873 /****************************************************************************
874  Send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call.
875 ****************************************************************************/
876
877 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
878 {
879         unsigned int data_len = 0;
880         unsigned int param_len = 0;
881         uint16 setup = TRANSACT2_QPATHINFO;
882         pstring param;
883         char *rparam=NULL, *rdata=NULL;
884         int count=8;
885         char *p;
886         BOOL ret;
887         unsigned int len;
888
889         p = param;
890         memset(p, 0, 6);
891         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
892         p += 6;
893         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
894
895         param_len = PTR_DIFF(p, param);
896
897         do {
898                 ret = (cli_send_trans(cli, SMBtrans2, 
899                                       NULL,           /* Name */
900                                       -1, 0,          /* fid, flags */
901                                       &setup, 1, 0,   /* setup, length, max */
902                                       param, param_len, 10, /* param, length, max */
903                                       NULL, data_len, cli->max_xmit /* data, length, max */
904                                       ) &&
905                        cli_receive_trans(cli, SMBtrans2, 
906                                          &rparam, &param_len,
907                                          &rdata, &data_len));
908                 if (!ret && cli_is_dos_error(cli)) {
909                         /* we need to work around a Win95 bug - sometimes
910                            it gives ERRSRV/ERRerror temprarily */
911                         uint8 eclass;
912                         uint32 ecode;
913                         cli_dos_error(cli, &eclass, &ecode);
914                         if (eclass != ERRSRV || ecode != ERRerror) break;
915                         smb_msleep(100);
916                 }
917         } while (count-- && ret==False);
918
919         if (!ret || !rdata || data_len < 4) {
920                 return NT_STATUS_UNSUCCESSFUL;
921         }
922
923         len = IVAL(rdata, 0);
924
925         if (len > data_len - 4) {
926                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
927         }
928
929         clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
930
931         SAFE_FREE(rdata);
932         SAFE_FREE(rparam);
933
934         return NT_STATUS_OK;
935 }