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