import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[metze/old/v3-2-winbind-ndr.git] / source / libsmb / clirap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client RAP calls
4    Copyright (C) Andrew Tridgell 1994-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #define NO_SYSLOG
22
23 #include "includes.h"
24
25
26 /****************************************************************************
27 Call a remote api on an arbitrary pipe.  takes param, data and setup buffers.
28 ****************************************************************************/
29 BOOL cli_api_pipe(struct cli_state *cli, const char *pipe_name, 
30                   uint16 *setup, uint32 setup_count, uint32 max_setup_count,
31                   char *params, uint32 param_count, uint32 max_param_count,
32                   char *data, uint32 data_count, uint32 max_data_count,
33                   char **rparam, uint32 *rparam_count,
34                   char **rdata, uint32 *rdata_count)
35 {
36   cli_send_trans(cli, SMBtrans, 
37                  pipe_name, 
38                  0,0,                         /* fid, flags */
39                  setup, setup_count, max_setup_count,
40                  params, param_count, max_param_count,
41                  data, data_count, max_data_count);
42
43   return (cli_receive_trans(cli, SMBtrans, 
44                             rparam, (unsigned int *)rparam_count,
45                             rdata, (unsigned int *)rdata_count));
46 }
47
48 /****************************************************************************
49 call a remote api
50 ****************************************************************************/
51 BOOL cli_api(struct cli_state *cli,
52              char *param, int prcnt, int mprcnt,
53              char *data, int drcnt, int mdrcnt,
54              char **rparam, unsigned int *rprcnt,
55              char **rdata, unsigned int *rdrcnt)
56 {
57   cli_send_trans(cli,SMBtrans,
58                  PIPE_LANMAN,             /* Name */
59                  0,0,                     /* fid, flags */
60                  NULL,0,0,                /* Setup, length, max */
61                  param, prcnt, mprcnt,    /* Params, length, max */
62                  data, drcnt, mdrcnt      /* Data, length, max */ 
63                 );
64
65   return (cli_receive_trans(cli,SMBtrans,
66                             rparam, rprcnt,
67                             rdata, rdrcnt));
68 }
69
70
71 /****************************************************************************
72 perform a NetWkstaUserLogon
73 ****************************************************************************/
74 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
75 {
76         char *rparam = NULL;
77         char *rdata = NULL;
78         char *p;
79         unsigned int rdrcnt,rprcnt;
80         pstring param;
81
82         memset(param, 0, sizeof(param));
83         
84         /* send a SMBtrans command with api NetWkstaUserLogon */
85         p = param;
86         SSVAL(p,0,132); /* api number */
87         p += 2;
88         pstrcpy_base(p,"OOWb54WrLh",param);
89         p = skip_string(p,1);
90         pstrcpy_base(p,"WB21BWDWWDDDDDDDzzzD",param);
91         p = skip_string(p,1);
92         SSVAL(p,0,1);
93         p += 2;
94         pstrcpy_base(p,user,param);
95         strupper_m(p);
96         p += 21;
97         p++;
98         p += 15;
99         p++; 
100         pstrcpy_base(p, workstation, param);
101         strupper_m(p);
102         p += 16;
103         SSVAL(p, 0, CLI_BUFFER_SIZE);
104         p += 2;
105         SSVAL(p, 0, CLI_BUFFER_SIZE);
106         p += 2;
107         
108         if (cli_api(cli, 
109                     param, PTR_DIFF(p,param),1024,  /* param, length, max */
110                     NULL, 0, CLI_BUFFER_SIZE,           /* data, length, max */
111                     &rparam, &rprcnt,               /* return params, return size */
112                     &rdata, &rdrcnt                 /* return data, return size */
113                    )) {
114                 cli->rap_error = rparam? SVAL(rparam,0) : -1;
115                 p = rdata;
116                 
117                 if (cli->rap_error == 0) {
118                         DEBUG(4,("NetWkstaUserLogon success\n"));
119                         cli->privileges = SVAL(p, 24);
120                         /* The cli->eff_name field used to be set here
121                            but it wasn't used anywhere else. */
122                 } else {
123                         DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
124                 }
125         }
126         
127         SAFE_FREE(rparam);
128         SAFE_FREE(rdata);
129         return (cli->rap_error == 0);
130 }
131
132 /****************************************************************************
133 call a NetShareEnum - try and browse available connections on a host
134 ****************************************************************************/
135 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(p,1);
150         pstrcpy_base(p,"B13BWz",param);
151         p = skip_string(p,1);
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 /****************************************************************************
202 call a NetServerEnum for the specified workgroup and servertype mask.  This
203 function then calls the specified callback function for each name returned.
204
205 The callback function takes 4 arguments: the machine name, the server type,
206 the comment and a state pointer.
207 ****************************************************************************/
208 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         /* send a SMBtrans command with api NetServerEnum */
221         p = param;
222         SSVAL(p,0,0x68); /* api number */
223         p += 2;
224         pstrcpy_base(p,"WrLehDz", param);
225         p = skip_string(p,1);
226   
227         pstrcpy_base(p,"B16BBDz", param);
228
229         p = skip_string(p,1);
230         SSVAL(p,0,uLevel);
231         SSVAL(p,2,CLI_BUFFER_SIZE);
232         p += 4;
233         SIVAL(p,0,stype);
234         p += 4;
235
236         p += push_ascii(p, workgroup, sizeof(pstring)-PTR_DIFF(p,param)-1, STR_TERMINATE|STR_UPPER);
237         
238         if (cli_api(cli, 
239                     param, PTR_DIFF(p,param), 8,        /* params, length, max */
240                     NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
241                     &rparam, &rprcnt,                   /* return params, return size */
242                     &rdata, &rdrcnt                     /* return data, return size */
243                    )) {
244                 int res = rparam? SVAL(rparam,0) : -1;
245                         
246                 if (res == 0 || res == ERRmoredata) {
247                         int i;
248                         int converter=SVAL(rparam,2);
249
250                         count=SVAL(rparam,4);
251                         p = rdata;
252                                         
253                         for (i = 0;i < count;i++, p += 26) {
254                                 char *sname = p;
255                                 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
256                                 const char *cmnt = comment_offset?(rdata+comment_offset):"";
257                                 pstring s1, s2;
258
259                                 if (comment_offset < 0 || comment_offset > (int)rdrcnt) continue;
260
261                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
262
263                                 pull_ascii_pstring(s1, sname);
264                                 pull_ascii_pstring(s2, cmnt);
265                                 fn(s1, stype, s2, state);
266                         }
267                 }
268         }
269   
270         SAFE_FREE(rparam);
271         SAFE_FREE(rdata);
272         
273         return(count > 0);
274 }
275
276
277
278 /****************************************************************************
279 Send a SamOEMChangePassword command
280 ****************************************************************************/
281 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
282                              const char *old_password)
283 {
284   pstring param;
285   char data[532];
286   char *p = param;
287   unsigned char old_pw_hash[16];
288   unsigned char new_pw_hash[16];
289   unsigned int data_len;
290   unsigned int param_len = 0;
291   char *rparam = NULL;
292   char *rdata = NULL;
293   unsigned int rprcnt, rdrcnt;
294
295   if (strlen(user) >= sizeof(fstring)-1) {
296     DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
297     return False;
298   }
299
300   SSVAL(p,0,214); /* SamOEMChangePassword command. */
301   p += 2;
302   pstrcpy_base(p, "zsT", param);
303   p = skip_string(p,1);
304   pstrcpy_base(p, "B516B16", param);
305   p = skip_string(p,1);
306   pstrcpy_base(p,user, param);
307   p = skip_string(p,1);
308   SSVAL(p,0,532);
309   p += 2;
310
311   param_len = PTR_DIFF(p,param);
312
313   /*
314    * Get the Lanman hash of the old password, we
315    * use this as the key to make_oem_passwd_hash().
316    */
317   E_deshash(old_password, old_pw_hash);
318
319   encode_pw_buffer(data, new_password, STR_ASCII);
320   
321 #ifdef DEBUG_PASSWORD
322   DEBUG(100,("make_oem_passwd_hash\n"));
323   dump_data(100, data, 516);
324 #endif
325   SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
326
327   /* 
328    * Now place the old password hash in the data.
329    */
330   E_deshash(new_password, new_pw_hash);
331
332   E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
333
334   data_len = 532;
335     
336   if (cli_send_trans(cli,SMBtrans,
337                     PIPE_LANMAN,                          /* name */
338                     0,0,                                  /* fid, flags */
339                     NULL,0,0,                             /* setup, length, max */
340                     param,param_len,2,                    /* param, length, max */
341                     data,data_len,0                       /* data, length, max */
342                    ) == False) {
343     DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
344               user ));
345     return False;
346   }
347
348   if (!cli_receive_trans(cli,SMBtrans,
349                        &rparam, &rprcnt,
350                        &rdata, &rdrcnt)) {
351           DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
352                    user ));
353           return False;
354   }
355   
356   if (rparam)
357           cli->rap_error = SVAL(rparam,0);
358   
359   SAFE_FREE(rparam);
360   SAFE_FREE(rdata);
361
362   return (cli->rap_error == 0);
363 }
364
365
366 /****************************************************************************
367 send a qpathinfo call
368 ****************************************************************************/
369 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
370                    time_t *c_time, time_t *a_time, time_t *m_time, 
371                    size_t *size, uint16 *mode)
372 {
373         unsigned int data_len = 0;
374         unsigned int param_len = 0;
375         unsigned int rparam_len, rdata_len;
376         uint16 setup = TRANSACT2_QPATHINFO;
377         pstring param;
378         char *rparam=NULL, *rdata=NULL;
379         int count=8;
380         BOOL ret;
381         time_t (*date_fn)(void *);
382         char *p;
383
384         p = param;
385         memset(p, 0, 6);
386         SSVAL(p, 0, SMB_INFO_STANDARD);
387         p += 6;
388         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
389
390         param_len = PTR_DIFF(p, param);
391
392         do {
393                 ret = (cli_send_trans(cli, SMBtrans2, 
394                                       NULL,           /* Name */
395                                       -1, 0,          /* fid, flags */
396                                       &setup, 1, 0,   /* setup, length, max */
397                                       param, param_len, 10, /* param, length, max */
398                                       NULL, data_len, cli->max_xmit /* data, length, max */
399                                       ) &&
400                        cli_receive_trans(cli, SMBtrans2, 
401                                          &rparam, &rparam_len,
402                                          &rdata, &rdata_len));
403                 if (!cli_is_dos_error(cli)) break;
404                 if (!ret) {
405                         /* we need to work around a Win95 bug - sometimes
406                            it gives ERRSRV/ERRerror temprarily */
407                         uint8 eclass;
408                         uint32 ecode;
409                         cli_dos_error(cli, &eclass, &ecode);
410                         if (eclass != ERRSRV || ecode != ERRerror) break;
411                         smb_msleep(100);
412                 }
413         } while (count-- && ret==False);
414
415         if (!ret || !rdata || rdata_len < 22) {
416                 return False;
417         }
418
419         if (cli->win95) {
420                 date_fn = make_unix_date;
421         } else {
422                 date_fn = make_unix_date2;
423         }
424
425         if (c_time) {
426                 *c_time = date_fn(rdata+0);
427         }
428         if (a_time) {
429                 *a_time = date_fn(rdata+4);
430         }
431         if (m_time) {
432                 *m_time = date_fn(rdata+8);
433         }
434         if (size) {
435                 *size = IVAL(rdata, 12);
436         }
437         if (mode) {
438                 *mode = SVAL(rdata,l1_attrFile);
439         }
440
441         SAFE_FREE(rdata);
442         SAFE_FREE(rparam);
443         return True;
444 }
445
446 /****************************************************************************
447 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
448 ****************************************************************************/
449 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, 
450                     time_t *c_time, time_t *a_time, time_t *m_time, 
451                     time_t *w_time, size_t *size, uint16 *mode,
452                     SMB_INO_T *ino)
453 {
454         unsigned int data_len = 0;
455         unsigned int param_len = 0;
456         uint16 setup = TRANSACT2_QPATHINFO;
457         pstring param;
458         char *rparam=NULL, *rdata=NULL;
459         char *p;
460
461         p = param;
462         memset(p, 0, 6);
463         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
464         p += 6;
465         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
466
467         param_len = PTR_DIFF(p, param);
468
469         if (!cli_send_trans(cli, SMBtrans2, 
470                             NULL,                         /* name */
471                             -1, 0,                        /* fid, flags */
472                             &setup, 1, 0,                 /* setup, length, max */
473                             param, param_len, 10,         /* param, length, max */
474                             NULL, data_len, cli->max_xmit /* data, length, max */
475                            )) {
476                 return False;
477         }
478
479         if (!cli_receive_trans(cli, SMBtrans2,
480                                &rparam, &param_len,
481                                &rdata, &data_len)) {
482                 return False;
483         }
484
485         if (!rdata || data_len < 22) {
486                 return False;
487         }
488
489         if (c_time) {
490                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
491         }
492         if (a_time) {
493                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
494         }
495         if (m_time) {
496                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
497         }
498         if (w_time) {
499                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
500         }
501         if (mode) {
502                 *mode = SVAL(rdata, 32);
503         }
504         if (size) {
505                 *size = IVAL(rdata, 48);
506         }
507         if (ino) {
508                 *ino = IVAL(rdata, 64);
509         }
510
511         SAFE_FREE(rdata);
512         SAFE_FREE(rparam);
513         return True;
514 }
515
516
517 /****************************************************************************
518 send a qfileinfo QUERY_FILE_NAME_INFO call
519 ****************************************************************************/
520 BOOL cli_qfilename(struct cli_state *cli, int fnum, 
521                    pstring name)
522 {
523         unsigned int data_len = 0;
524         unsigned int param_len = 0;
525         uint16 setup = TRANSACT2_QFILEINFO;
526         pstring param;
527         char *rparam=NULL, *rdata=NULL;
528
529         param_len = 4;
530         memset(param, 0, param_len);
531         SSVAL(param, 0, fnum);
532         SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
533
534         if (!cli_send_trans(cli, SMBtrans2, 
535                             NULL,                           /* name */
536                             -1, 0,                          /* fid, flags */
537                             &setup, 1, 0,                   /* setup, length, max */
538                             param, param_len, 2,            /* param, length, max */
539                             NULL, data_len, cli->max_xmit   /* data, length, max */
540                            )) {
541                 return False;
542         }
543
544         if (!cli_receive_trans(cli, SMBtrans2,
545                                &rparam, &param_len,
546                                &rdata, &data_len)) {
547                 return False;
548         }
549
550         if (!rdata || data_len < 4) {
551                 return False;
552         }
553
554         clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE);
555
556         return True;
557 }
558
559
560 /****************************************************************************
561 send a qfileinfo call
562 ****************************************************************************/
563 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
564                    uint16 *mode, size_t *size,
565                    time_t *c_time, time_t *a_time, time_t *m_time, 
566                    time_t *w_time, SMB_INO_T *ino)
567 {
568         unsigned int data_len = 0;
569         unsigned int param_len = 0;
570         uint16 setup = TRANSACT2_QFILEINFO;
571         pstring param;
572         char *rparam=NULL, *rdata=NULL;
573
574         /* if its a win95 server then fail this - win95 totally screws it
575            up */
576         if (cli->win95) return False;
577
578         param_len = 4;
579
580         memset(param, 0, param_len);
581         SSVAL(param, 0, fnum);
582         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
583
584         if (!cli_send_trans(cli, SMBtrans2, 
585                             NULL,                           /* name */
586                             -1, 0,                          /* fid, flags */
587                             &setup, 1, 0,                   /* setup, length, max */
588                             param, param_len, 2,            /* param, length, max */
589                             NULL, data_len, cli->max_xmit   /* data, length, max */
590                            )) {
591                 return False;
592         }
593
594         if (!cli_receive_trans(cli, SMBtrans2,
595                                &rparam, &param_len,
596                                &rdata, &data_len)) {
597                 return False;
598         }
599
600         if (!rdata || data_len < 68) {
601                 return False;
602         }
603
604         if (c_time) {
605                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
606         }
607         if (a_time) {
608                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
609         }
610         if (m_time) {
611                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
612         }
613         if (w_time) {
614                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
615         }
616         if (mode) {
617                 *mode = SVAL(rdata, 32);
618         }
619         if (size) {
620                 *size = IVAL(rdata, 48);
621         }
622         if (ino) {
623                 *ino = IVAL(rdata, 64);
624         }
625
626         SAFE_FREE(rdata);
627         SAFE_FREE(rparam);
628         return True;
629 }
630
631 /****************************************************************************
632 send a qfileinfo call
633 ****************************************************************************/
634 BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
635 {
636         unsigned int data_len = 0;
637         unsigned int param_len = 0;
638         uint16 setup = TRANSACT2_QFILEINFO;
639         pstring param;
640         char *rparam=NULL, *rdata=NULL;
641
642         *poutdata = NULL;
643         *poutlen = 0;
644
645         /* if its a win95 server then fail this - win95 totally screws it
646            up */
647         if (cli->win95)
648                 return False;
649
650         param_len = 4;
651
652         memset(param, 0, param_len);
653         SSVAL(param, 0, fnum);
654         SSVAL(param, 2, level);
655
656         if (!cli_send_trans(cli, SMBtrans2, 
657                             NULL,                           /* name */
658                             -1, 0,                          /* fid, flags */
659                             &setup, 1, 0,                   /* setup, length, max */
660                             param, param_len, 2,            /* param, length, max */
661                             NULL, data_len, cli->max_xmit   /* data, length, max */
662                            )) {
663                 return False;
664         }
665
666         if (!cli_receive_trans(cli, SMBtrans2,
667                                &rparam, &param_len,
668                                &rdata, &data_len)) {
669                 return False;
670         }
671
672         *poutdata = memdup(rdata, data_len);
673         *poutlen = data_len;
674
675         SAFE_FREE(rdata);
676         SAFE_FREE(rparam);
677         return True;
678 }
679
680
681
682 /****************************************************************************
683 send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
684 ****************************************************************************/
685 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
686 {
687         unsigned int data_len = 0;
688         unsigned int param_len = 0;
689         uint16 setup = TRANSACT2_QPATHINFO;
690         pstring param;
691         char *rparam=NULL, *rdata=NULL;
692         int count=8;
693         char *p;
694         BOOL ret;
695         unsigned int len;
696
697         p = param;
698         memset(p, 0, 6);
699         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
700         p += 6;
701         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
702
703         param_len = PTR_DIFF(p, param);
704
705         do {
706                 ret = (cli_send_trans(cli, SMBtrans2, 
707                                       NULL,           /* Name */
708                                       -1, 0,          /* fid, flags */
709                                       &setup, 1, 0,   /* setup, length, max */
710                                       param, param_len, 10, /* param, length, max */
711                                       NULL, data_len, cli->max_xmit /* data, length, max */
712                                       ) &&
713                        cli_receive_trans(cli, SMBtrans2, 
714                                          &rparam, &param_len,
715                                          &rdata, &data_len));
716                 if (!ret && cli_is_dos_error(cli)) {
717                         /* we need to work around a Win95 bug - sometimes
718                            it gives ERRSRV/ERRerror temprarily */
719                         uint8 eclass;
720                         uint32 ecode;
721                         cli_dos_error(cli, &eclass, &ecode);
722                         if (eclass != ERRSRV || ecode != ERRerror) break;
723                         smb_msleep(100);
724                 }
725         } while (count-- && ret==False);
726
727         if (!ret || !rdata || data_len < 4) {
728                 return NT_STATUS_UNSUCCESSFUL;
729         }
730
731         len = IVAL(rdata, 0);
732
733         if (len > data_len - 4) {
734                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
735         }
736
737         clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
738
739         SAFE_FREE(rdata);
740         SAFE_FREE(rparam);
741
742         return NT_STATUS_OK;
743 }