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