r5968: derrell's large file fix for libsmbclient (BUG 2505)
[abartlet/samba.git/.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 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 #define NO_SYSLOG
23
24 #include "includes.h"
25
26
27 /****************************************************************************
28 Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
29 ****************************************************************************/
30 BOOL cli_api_pipe(struct cli_state *cli, const char *pipe_name, 
31                   uint16 *setup, uint32 setup_count, uint32 max_setup_count,
32                   char *params, uint32 param_count, uint32 max_param_count,
33                   char *data, uint32 data_count, uint32 max_data_count,
34                   char **rparam, uint32 *rparam_count,
35                   char **rdata, uint32 *rdata_count)
36 {
37   cli_send_trans(cli, SMBtrans, 
38                  pipe_name, 
39                  0,0,                         /* fid, flags */
40                  setup, setup_count, max_setup_count,
41                  params, param_count, max_param_count,
42                  data, data_count, max_data_count);
43
44   return (cli_receive_trans(cli, SMBtrans, 
45                             rparam, (unsigned int *)rparam_count,
46                             rdata, (unsigned int *)rdata_count));
47 }
48
49 /****************************************************************************
50 call a remote api
51 ****************************************************************************/
52 BOOL cli_api(struct cli_state *cli,
53              char *param, int prcnt, int mprcnt,
54              char *data, int drcnt, int mdrcnt,
55              char **rparam, unsigned int *rprcnt,
56              char **rdata, unsigned int *rdrcnt)
57 {
58   cli_send_trans(cli,SMBtrans,
59                  PIPE_LANMAN,             /* Name */
60                  0,0,                     /* fid, flags */
61                  NULL,0,0,                /* Setup, length, max */
62                  param, prcnt, mprcnt,    /* Params, length, max */
63                  data, drcnt, mdrcnt      /* Data, length, max */ 
64                 );
65
66   return (cli_receive_trans(cli,SMBtrans,
67                             rparam, rprcnt,
68                             rdata, rdrcnt));
69 }
70
71
72 /****************************************************************************
73 perform a NetWkstaUserLogon
74 ****************************************************************************/
75 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
76 {
77         char *rparam = NULL;
78         char *rdata = NULL;
79         char *p;
80         unsigned int rdrcnt,rprcnt;
81         pstring param;
82
83         memset(param, 0, sizeof(param));
84         
85         /* send a SMBtrans command with api NetWkstaUserLogon */
86         p = param;
87         SSVAL(p,0,132); /* api number */
88         p += 2;
89         pstrcpy_base(p,"OOWb54WrLh",param);
90         p = skip_string(p,1);
91         pstrcpy_base(p,"WB21BWDWWDDDDDDDzzzD",param);
92         p = skip_string(p,1);
93         SSVAL(p,0,1);
94         p += 2;
95         pstrcpy_base(p,user,param);
96         strupper_m(p);
97         p += 21;
98         p++;
99         p += 15;
100         p++; 
101         pstrcpy_base(p, workstation, param);
102         strupper_m(p);
103         p += 16;
104         SSVAL(p, 0, CLI_BUFFER_SIZE);
105         p += 2;
106         SSVAL(p, 0, CLI_BUFFER_SIZE);
107         p += 2;
108         
109         if (cli_api(cli, 
110                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
111                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
112                     &rparam, &rprcnt,               /* return params, return size */
113                     &rdata, &rdrcnt                 /* return data, return size */
114                    )) {
115                 cli->rap_error = rparam? SVAL(rparam,0) : -1;
116                 p = rdata;
117                 
118                 if (cli->rap_error == 0) {
119                         DEBUG(4,("NetWkstaUserLogon success\n"));
120                         cli->privileges = SVAL(p, 24);
121                         /* The cli->eff_name field used to be set here
122                            but it wasn't used anywhere else. */
123                 } else {
124                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
125                 }
126         }
127         
128         SAFE_FREE(rparam);
129         SAFE_FREE(rdata);
130         return (cli->rap_error == 0);
131 }
132
133 /****************************************************************************
134 call a NetShareEnum - try and browse available connections on a host
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(p,1);
151         pstrcpy_base(p,"B13BWz",param);
152         p = skip_string(p,1);
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 /****************************************************************************
203 call a NetServerEnum for the specified workgroup and servertype mask.  This
204 function then calls the specified callback function for each name returned.
205
206 The callback function takes 4 arguments: the machine name, the server type,
207 the comment and a state pointer.
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(p,1);
229   
230         pstrcpy_base(p,"B16BBDz", param);
231
232         p = skip_string(p,1);
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                         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
292 /****************************************************************************
293 Send a SamOEMChangePassword command
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   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(p,1);
318   pstrcpy_base(p, "B516B16", param);
319   p = skip_string(p,1);
320   pstrcpy_base(p,user, param);
321   p = skip_string(p,1);
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                     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   SAFE_FREE(rparam);
374   SAFE_FREE(rdata);
375
376   return (cli->rap_error == 0);
377 }
378
379
380 /****************************************************************************
381 send a qpathinfo call
382 ****************************************************************************/
383 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
384                    time_t *c_time, time_t *a_time, time_t *m_time, 
385                    SMB_OFF_T *size, uint16 *mode)
386 {
387         unsigned int data_len = 0;
388         unsigned int param_len = 0;
389         unsigned int rparam_len, rdata_len;
390         uint16 setup = TRANSACT2_QPATHINFO;
391         pstring param;
392         char *rparam=NULL, *rdata=NULL;
393         int count=8;
394         BOOL ret;
395         time_t (*date_fn)(void *);
396         char *p;
397
398         p = param;
399         memset(p, 0, 6);
400         SSVAL(p, 0, SMB_INFO_STANDARD);
401         p += 6;
402         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
403
404         param_len = PTR_DIFF(p, param);
405
406         do {
407                 ret = (cli_send_trans(cli, SMBtrans2, 
408                                       NULL,           /* Name */
409                                       -1, 0,          /* fid, flags */
410                                       &setup, 1, 0,   /* setup, length, max */
411                                       param, param_len, 10, /* param, length, max */
412                                       NULL, data_len, cli->max_xmit /* data, length, max */
413                                       ) &&
414                        cli_receive_trans(cli, SMBtrans2, 
415                                          &rparam, &rparam_len,
416                                          &rdata, &rdata_len));
417                 if (!cli_is_dos_error(cli)) break;
418                 if (!ret) {
419                         /* we need to work around a Win95 bug - sometimes
420                            it gives ERRSRV/ERRerror temprarily */
421                         uint8 eclass;
422                         uint32 ecode;
423                         cli_dos_error(cli, &eclass, &ecode);
424                         if (eclass != ERRSRV || ecode != ERRerror) break;
425                         smb_msleep(100);
426                 }
427         } while (count-- && ret==False);
428
429         if (!ret || !rdata || rdata_len < 22) {
430                 return False;
431         }
432
433         if (cli->win95) {
434                 date_fn = make_unix_date;
435         } else {
436                 date_fn = make_unix_date2;
437         }
438
439         if (c_time) {
440                 *c_time = date_fn(rdata+0);
441         }
442         if (a_time) {
443                 *a_time = date_fn(rdata+4);
444         }
445         if (m_time) {
446                 *m_time = date_fn(rdata+8);
447         }
448         if (size) {
449                 *size = IVAL(rdata, 12);
450         }
451         if (mode) {
452                 *mode = SVAL(rdata,l1_attrFile);
453         }
454
455         SAFE_FREE(rdata);
456         SAFE_FREE(rparam);
457         return True;
458 }
459
460 /****************************************************************************
461 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
462 ****************************************************************************/
463 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, 
464                     time_t *c_time, time_t *a_time, time_t *m_time, 
465                     time_t *w_time, SMB_OFF_T *size, uint16 *mode,
466                     SMB_INO_T *ino)
467 {
468         unsigned int data_len = 0;
469         unsigned int param_len = 0;
470         uint16 setup = TRANSACT2_QPATHINFO;
471         pstring param;
472         char *rparam=NULL, *rdata=NULL;
473         char *p;
474
475         p = param;
476         memset(p, 0, 6);
477         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
478         p += 6;
479         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
480
481         param_len = PTR_DIFF(p, param);
482
483         if (!cli_send_trans(cli, SMBtrans2, 
484                             NULL,                         /* name */
485                             -1, 0,                        /* fid, flags */
486                             &setup, 1, 0,                 /* setup, length, max */
487                             param, param_len, 10,         /* param, length, max */
488                             NULL, data_len, cli->max_xmit /* data, length, max */
489                            )) {
490                 return False;
491         }
492
493         if (!cli_receive_trans(cli, SMBtrans2,
494                                &rparam, &param_len,
495                                &rdata, &data_len)) {
496                 return False;
497         }
498
499         if (!rdata || data_len < 22) {
500                 return False;
501         }
502
503         if (c_time) {
504                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
505         }
506         if (a_time) {
507                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
508         }
509         if (m_time) {
510                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
511         }
512         if (w_time) {
513                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
514         }
515         if (mode) {
516                 *mode = SVAL(rdata, 32);
517         }
518         if (size) {
519                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
520         }
521         if (ino) {
522                 *ino = IVAL(rdata, 64);
523         }
524
525         SAFE_FREE(rdata);
526         SAFE_FREE(rparam);
527         return True;
528 }
529
530
531 /****************************************************************************
532 send a qfileinfo QUERY_FILE_NAME_INFO call
533 ****************************************************************************/
534 BOOL cli_qfilename(struct cli_state *cli, int fnum, 
535                    pstring name)
536 {
537         unsigned int data_len = 0;
538         unsigned int param_len = 0;
539         uint16 setup = TRANSACT2_QFILEINFO;
540         pstring param;
541         char *rparam=NULL, *rdata=NULL;
542
543         param_len = 4;
544         memset(param, 0, param_len);
545         SSVAL(param, 0, fnum);
546         SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
547
548         if (!cli_send_trans(cli, SMBtrans2, 
549                             NULL,                         /* name */
550                             -1, 0,                        /* fid, flags */
551                             &setup, 1, 0,                 /* setup, length, max */
552                             param, param_len, 2,          /* param, length, max */
553                             NULL, data_len, cli->max_xmit /* data, length, max */
554                            )) {
555                 return False;
556         }
557
558         if (!cli_receive_trans(cli, SMBtrans2,
559                                &rparam, &param_len,
560                                &rdata, &data_len)) {
561                 return False;
562         }
563
564         if (!rdata || data_len < 4) {
565                 return False;
566         }
567
568         clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE);
569
570         return True;
571 }
572
573
574 /****************************************************************************
575 send a qfileinfo call
576 ****************************************************************************/
577 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
578                    uint16 *mode, SMB_OFF_T *size,
579                    time_t *c_time, time_t *a_time, time_t *m_time, 
580                    time_t *w_time, SMB_INO_T *ino)
581 {
582         unsigned int data_len = 0;
583         unsigned int param_len = 0;
584         uint16 setup = TRANSACT2_QFILEINFO;
585         pstring param;
586         char *rparam=NULL, *rdata=NULL;
587
588         /* if its a win95 server then fail this - win95 totally screws it
589            up */
590         if (cli->win95) return False;
591
592         param_len = 4;
593
594         memset(param, 0, param_len);
595         SSVAL(param, 0, fnum);
596         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
597
598         if (!cli_send_trans(cli, SMBtrans2, 
599                             NULL,                         /* name */
600                             -1, 0,                        /* fid, flags */
601                             &setup, 1, 0,                 /* setup, length, max */
602                             param, param_len, 2,          /* param, length, max */
603                             NULL, data_len, cli->max_xmit /* data, length, max */
604                            )) {
605                 return False;
606         }
607
608         if (!cli_receive_trans(cli, SMBtrans2,
609                                &rparam, &param_len,
610                                &rdata, &data_len)) {
611                 return False;
612         }
613
614         if (!rdata || data_len < 68) {
615                 return False;
616         }
617
618         if (c_time) {
619                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
620         }
621         if (a_time) {
622                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
623         }
624         if (m_time) {
625                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
626         }
627         if (w_time) {
628                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
629         }
630         if (mode) {
631                 *mode = SVAL(rdata, 32);
632         }
633         if (size) {
634                 *size = IVAL2_TO_SMB_BIG_UINT(rdata,48);
635         }
636         if (ino) {
637                 *ino = IVAL(rdata, 64);
638         }
639
640         SAFE_FREE(rdata);
641         SAFE_FREE(rparam);
642         return True;
643 }
644
645
646 /****************************************************************************
647 send a qpathinfo BASIC_INFO call
648 ****************************************************************************/
649 BOOL cli_qpathinfo_basic( struct cli_state *cli, const char *name, 
650                           SMB_STRUCT_STAT *sbuf, uint32 *attributes )
651 {
652         unsigned int param_len = 0;
653         unsigned int data_len = 0;
654         uint16 setup = TRANSACT2_QPATHINFO;
655         char param[sizeof(pstring)+6];
656         char *rparam=NULL, *rdata=NULL;
657         char *p;
658         pstring path;
659         int len;
660         
661         /* send full paths to dfs root shares */
662         
663         if ( cli->dfsroot )
664                 pstr_sprintf(path, "\\%s\\%s\\%s", cli->desthost, cli->share, name );
665         else
666                 pstrcpy( path, name );
667         
668         /* cleanup */
669         
670         len = strlen( path );
671         if ( path[len] == '\\' )
672                 path[len] = '\0';
673
674         p = param;
675         memset(p, 0, 6);
676         SSVAL(p, 0, SMB_QUERY_FILE_BASIC_INFO);
677         p += 6;
678         p += clistr_push(cli, p, path, sizeof(pstring)-6, STR_TERMINATE);
679         param_len = PTR_DIFF(p, param);
680
681         if (!cli_send_trans(cli, SMBtrans2,
682                 NULL,                        /* name */
683                 -1, 0,                       /* fid, flags */
684                 &setup, 1, 0,                /* setup, length, max */
685                 param, param_len, 2,         /* param, length, max */
686                 NULL,  0, cli->max_xmit      /* data, length, max */
687                 )) {
688                         return False;
689         }
690
691         if (!cli_receive_trans(cli, SMBtrans2,
692                 &rparam, &param_len,
693                 &rdata, &data_len)) {
694                         return False;
695         }
696
697         if (data_len < 36) {
698                 SAFE_FREE(rdata);
699                 SAFE_FREE(rparam);
700                 return False;
701         }
702
703         sbuf->st_atime = interpret_long_date( rdata+8 );
704         sbuf->st_mtime = interpret_long_date( rdata+16 );
705         sbuf->st_ctime = interpret_long_date( rdata+24 );
706         
707         *attributes = IVAL( rdata, 32 );
708         
709         SAFE_FREE(rparam);
710         SAFE_FREE(rdata);
711         
712         return True;
713 }
714
715 /****************************************************************************
716 send a qfileinfo call
717 ****************************************************************************/
718
719 BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
720 {
721         unsigned int data_len = 0;
722         unsigned int param_len = 0;
723         uint16 setup = TRANSACT2_QFILEINFO;
724         pstring param;
725         char *rparam=NULL, *rdata=NULL;
726
727         *poutdata = NULL;
728         *poutlen = 0;
729
730         /* if its a win95 server then fail this - win95 totally screws it
731            up */
732         if (cli->win95)
733                 return False;
734
735         param_len = 4;
736
737         memset(param, 0, param_len);
738         SSVAL(param, 0, fnum);
739         SSVAL(param, 2, level);
740
741         if (!cli_send_trans(cli, SMBtrans2, 
742                             NULL,                           /* name */
743                             -1, 0,                          /* fid, flags */
744                             &setup, 1, 0,                   /* setup, length, max */
745                             param, param_len, 2,            /* param, length, max */
746                             NULL, data_len, cli->max_xmit   /* data, length, max */
747                            )) {
748                 return False;
749         }
750
751         if (!cli_receive_trans(cli, SMBtrans2,
752                                &rparam, &param_len,
753                                &rdata, &data_len)) {
754                 return False;
755         }
756
757         *poutdata = memdup(rdata, data_len);
758         *poutlen = data_len;
759
760         SAFE_FREE(rdata);
761         SAFE_FREE(rparam);
762         return True;
763 }
764
765
766
767 /****************************************************************************
768 send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
769 ****************************************************************************/
770 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
771 {
772         unsigned int data_len = 0;
773         unsigned int param_len = 0;
774         uint16 setup = TRANSACT2_QPATHINFO;
775         pstring param;
776         char *rparam=NULL, *rdata=NULL;
777         int count=8;
778         char *p;
779         BOOL ret;
780         unsigned int len;
781
782         p = param;
783         memset(p, 0, 6);
784         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
785         p += 6;
786         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
787
788         param_len = PTR_DIFF(p, param);
789
790         do {
791                 ret = (cli_send_trans(cli, SMBtrans2, 
792                                       NULL,           /* Name */
793                                       -1, 0,          /* fid, flags */
794                                       &setup, 1, 0,   /* setup, length, max */
795                                       param, param_len, 10, /* param, length, max */
796                                       NULL, data_len, cli->max_xmit /* data, length, max */
797                                       ) &&
798                        cli_receive_trans(cli, SMBtrans2, 
799                                          &rparam, &param_len,
800                                          &rdata, &data_len));
801                 if (!ret && cli_is_dos_error(cli)) {
802                         /* we need to work around a Win95 bug - sometimes
803                            it gives ERRSRV/ERRerror temprarily */
804                         uint8 eclass;
805                         uint32 ecode;
806                         cli_dos_error(cli, &eclass, &ecode);
807                         if (eclass != ERRSRV || ecode != ERRerror) break;
808                         smb_msleep(100);
809                 }
810         } while (count-- && ret==False);
811
812         if (!ret || !rdata || data_len < 4) {
813                 return NT_STATUS_UNSUCCESSFUL;
814         }
815
816         len = IVAL(rdata, 0);
817
818         if (len > data_len - 4) {
819                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
820         }
821
822         clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
823
824         SAFE_FREE(rdata);
825         SAFE_FREE(rparam);
826
827         return NT_STATUS_OK;
828 }