8cc5d8bf9016e4c31227f863381329820f55824f
[tprouty/samba.git] / source / libsmb / clirap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client RAP calls
4    Copyright (C) Andrew Tridgell 1994-1998
5    
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         errno = 0; /* reset */
221
222         /* send a SMBtrans command with api NetServerEnum */
223         p = param;
224         SSVAL(p,0,0x68); /* api number */
225         p += 2;
226         pstrcpy_base(p,"WrLehDz", param);
227         p = skip_string(p,1);
228   
229         pstrcpy_base(p,"B16BBDz", param);
230
231         p = skip_string(p,1);
232         SSVAL(p,0,uLevel);
233         SSVAL(p,2,CLI_BUFFER_SIZE);
234         p += 4;
235         SIVAL(p,0,stype);
236         p += 4;
237
238         p += push_ascii(p, workgroup, sizeof(pstring)-PTR_DIFF(p,param)-1, STR_TERMINATE|STR_UPPER);
239         
240         if (cli_api(cli, 
241                     param, PTR_DIFF(p,param), 8,        /* params, length, max */
242                     NULL, 0, CLI_BUFFER_SIZE,               /* data, length, max */
243                     &rparam, &rprcnt,                   /* return params, return size */
244                     &rdata, &rdrcnt                     /* return data, return size */
245                    )) {
246                 int res = rparam? SVAL(rparam,0) : -1;
247                         
248                 if (res == 0 || res == ERRmoredata) {
249                         int i;
250                         int converter=SVAL(rparam,2);
251
252                         count=SVAL(rparam,4);
253                         p = rdata;
254                                         
255                         for (i = 0;i < count;i++, p += 26) {
256                                 char *sname = p;
257                                 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
258                                 const char *cmnt = comment_offset?(rdata+comment_offset):"";
259                                 pstring s1, s2;
260
261                                 if (comment_offset < 0 || comment_offset > (int)rdrcnt) continue;
262
263                                 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
264
265                                 pull_ascii_pstring(s1, sname);
266                                 pull_ascii_pstring(s2, cmnt);
267                                 fn(s1, stype, s2, state);
268                         }
269                 }
270         }
271   
272         SAFE_FREE(rparam);
273         SAFE_FREE(rdata);
274
275         if (count < 0) {
276             errno = cli_errno(cli);
277         } else {
278             if (!count) {
279                 /* this is a very special case, when the domain master for the 
280                    work group isn't part of the work group itself, there is something
281                    wild going on */
282                 errno = ENOENT;
283             }
284         }
285                         
286         return(count > 0);
287 }
288
289
290
291 /****************************************************************************
292 Send a SamOEMChangePassword command
293 ****************************************************************************/
294 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
295                              const char *old_password)
296 {
297   pstring param;
298   char data[532];
299   char *p = param;
300   unsigned char old_pw_hash[16];
301   unsigned char new_pw_hash[16];
302   unsigned int data_len;
303   unsigned int param_len = 0;
304   char *rparam = NULL;
305   char *rdata = NULL;
306   unsigned int rprcnt, rdrcnt;
307
308   if (strlen(user) >= sizeof(fstring)-1) {
309     DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
310     return False;
311   }
312
313   SSVAL(p,0,214); /* SamOEMChangePassword command. */
314   p += 2;
315   pstrcpy_base(p, "zsT", param);
316   p = skip_string(p,1);
317   pstrcpy_base(p, "B516B16", param);
318   p = skip_string(p,1);
319   pstrcpy_base(p,user, param);
320   p = skip_string(p,1);
321   SSVAL(p,0,532);
322   p += 2;
323
324   param_len = PTR_DIFF(p,param);
325
326   /*
327    * Get the Lanman hash of the old password, we
328    * use this as the key to make_oem_passwd_hash().
329    */
330   E_deshash(old_password, old_pw_hash);
331
332   encode_pw_buffer(data, new_password, STR_ASCII);
333   
334 #ifdef DEBUG_PASSWORD
335   DEBUG(100,("make_oem_passwd_hash\n"));
336   dump_data(100, data, 516);
337 #endif
338   SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516);
339
340   /* 
341    * Now place the old password hash in the data.
342    */
343   E_deshash(new_password, new_pw_hash);
344
345   E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
346
347   data_len = 532;
348     
349   if (cli_send_trans(cli,SMBtrans,
350                     PIPE_LANMAN,                          /* name */
351                     0,0,                                  /* fid, flags */
352                     NULL,0,0,                             /* setup, length, max */
353                     param,param_len,2,                    /* param, length, max */
354                     data,data_len,0                       /* data, length, max */
355                    ) == False) {
356     DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
357               user ));
358     return False;
359   }
360
361   if (!cli_receive_trans(cli,SMBtrans,
362                        &rparam, &rprcnt,
363                        &rdata, &rdrcnt)) {
364           DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n",
365                    user ));
366           return False;
367   }
368   
369   if (rparam)
370           cli->rap_error = SVAL(rparam,0);
371   
372   SAFE_FREE(rparam);
373   SAFE_FREE(rdata);
374
375   return (cli->rap_error == 0);
376 }
377
378
379 /****************************************************************************
380 send a qpathinfo call
381 ****************************************************************************/
382 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname, 
383                    time_t *c_time, time_t *a_time, time_t *m_time, 
384                    size_t *size, uint16 *mode)
385 {
386         unsigned int data_len = 0;
387         unsigned int param_len = 0;
388         unsigned int rparam_len, rdata_len;
389         uint16 setup = TRANSACT2_QPATHINFO;
390         pstring param;
391         char *rparam=NULL, *rdata=NULL;
392         int count=8;
393         BOOL ret;
394         time_t (*date_fn)(void *);
395         char *p;
396
397         p = param;
398         memset(p, 0, 6);
399         SSVAL(p, 0, SMB_INFO_STANDARD);
400         p += 6;
401         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
402
403         param_len = PTR_DIFF(p, param);
404
405         do {
406                 ret = (cli_send_trans(cli, SMBtrans2, 
407                                       NULL,           /* Name */
408                                       -1, 0,          /* fid, flags */
409                                       &setup, 1, 0,   /* setup, length, max */
410                                       param, param_len, 10, /* param, length, max */
411                                       NULL, data_len, cli->max_xmit /* data, length, max */
412                                       ) &&
413                        cli_receive_trans(cli, SMBtrans2, 
414                                          &rparam, &rparam_len,
415                                          &rdata, &rdata_len));
416                 if (!cli_is_dos_error(cli)) break;
417                 if (!ret) {
418                         /* we need to work around a Win95 bug - sometimes
419                            it gives ERRSRV/ERRerror temprarily */
420                         uint8 eclass;
421                         uint32 ecode;
422                         cli_dos_error(cli, &eclass, &ecode);
423                         if (eclass != ERRSRV || ecode != ERRerror) break;
424                         smb_msleep(100);
425                 }
426         } while (count-- && ret==False);
427
428         if (!ret || !rdata || rdata_len < 22) {
429                 return False;
430         }
431
432         if (cli->win95) {
433                 date_fn = make_unix_date;
434         } else {
435                 date_fn = make_unix_date2;
436         }
437
438         if (c_time) {
439                 *c_time = date_fn(rdata+0);
440         }
441         if (a_time) {
442                 *a_time = date_fn(rdata+4);
443         }
444         if (m_time) {
445                 *m_time = date_fn(rdata+8);
446         }
447         if (size) {
448                 *size = IVAL(rdata, 12);
449         }
450         if (mode) {
451                 *mode = SVAL(rdata,l1_attrFile);
452         }
453
454         SAFE_FREE(rdata);
455         SAFE_FREE(rparam);
456         return True;
457 }
458
459 /****************************************************************************
460 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
461 ****************************************************************************/
462 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname, 
463                     time_t *c_time, time_t *a_time, time_t *m_time, 
464                     time_t *w_time, size_t *size, uint16 *mode,
465                     SMB_INO_T *ino)
466 {
467         unsigned int data_len = 0;
468         unsigned int param_len = 0;
469         uint16 setup = TRANSACT2_QPATHINFO;
470         pstring param;
471         char *rparam=NULL, *rdata=NULL;
472         char *p;
473
474         p = param;
475         memset(p, 0, 6);
476         SSVAL(p, 0, SMB_QUERY_FILE_ALL_INFO);
477         p += 6;
478         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
479
480         param_len = PTR_DIFF(p, param);
481
482         if (!cli_send_trans(cli, SMBtrans2, 
483                             NULL,                         /* name */
484                             -1, 0,                        /* fid, flags */
485                             &setup, 1, 0,                 /* setup, length, max */
486                             param, param_len, 10,         /* param, length, max */
487                             NULL, data_len, cli->max_xmit /* data, length, max */
488                            )) {
489                 return False;
490         }
491
492         if (!cli_receive_trans(cli, SMBtrans2,
493                                &rparam, &param_len,
494                                &rdata, &data_len)) {
495                 return False;
496         }
497
498         if (!rdata || data_len < 22) {
499                 return False;
500         }
501
502         if (c_time) {
503                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
504         }
505         if (a_time) {
506                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
507         }
508         if (m_time) {
509                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
510         }
511         if (w_time) {
512                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
513         }
514         if (mode) {
515                 *mode = SVAL(rdata, 32);
516         }
517         if (size) {
518                 *size = IVAL(rdata, 48);
519         }
520         if (ino) {
521                 *ino = IVAL(rdata, 64);
522         }
523
524         SAFE_FREE(rdata);
525         SAFE_FREE(rparam);
526         return True;
527 }
528
529
530 /****************************************************************************
531 send a qfileinfo QUERY_FILE_NAME_INFO call
532 ****************************************************************************/
533 BOOL cli_qfilename(struct cli_state *cli, int fnum, 
534                    pstring name)
535 {
536         unsigned int data_len = 0;
537         unsigned int param_len = 0;
538         uint16 setup = TRANSACT2_QFILEINFO;
539         pstring param;
540         char *rparam=NULL, *rdata=NULL;
541
542         param_len = 4;
543         memset(param, 0, param_len);
544         SSVAL(param, 0, fnum);
545         SSVAL(param, 2, SMB_QUERY_FILE_NAME_INFO);
546
547         if (!cli_send_trans(cli, SMBtrans2, 
548                             NULL,                           /* name */
549                             -1, 0,                          /* fid, flags */
550                             &setup, 1, 0,                   /* setup, length, max */
551                             param, param_len, 2,            /* param, length, max */
552                             NULL, data_len, cli->max_xmit   /* data, length, max */
553                            )) {
554                 return False;
555         }
556
557         if (!cli_receive_trans(cli, SMBtrans2,
558                                &rparam, &param_len,
559                                &rdata, &data_len)) {
560                 return False;
561         }
562
563         if (!rdata || data_len < 4) {
564                 return False;
565         }
566
567         clistr_pull(cli, name, rdata+4, sizeof(pstring), IVAL(rdata, 0), STR_UNICODE);
568
569         return True;
570 }
571
572
573 /****************************************************************************
574 send a qfileinfo call
575 ****************************************************************************/
576 BOOL cli_qfileinfo(struct cli_state *cli, int fnum, 
577                    uint16 *mode, size_t *size,
578                    time_t *c_time, time_t *a_time, time_t *m_time, 
579                    time_t *w_time, SMB_INO_T *ino)
580 {
581         unsigned int data_len = 0;
582         unsigned int param_len = 0;
583         uint16 setup = TRANSACT2_QFILEINFO;
584         pstring param;
585         char *rparam=NULL, *rdata=NULL;
586
587         /* if its a win95 server then fail this - win95 totally screws it
588            up */
589         if (cli->win95) return False;
590
591         param_len = 4;
592
593         memset(param, 0, param_len);
594         SSVAL(param, 0, fnum);
595         SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
596
597         if (!cli_send_trans(cli, SMBtrans2, 
598                             NULL,                           /* name */
599                             -1, 0,                          /* fid, flags */
600                             &setup, 1, 0,                   /* setup, length, max */
601                             param, param_len, 2,            /* param, length, max */
602                             NULL, data_len, cli->max_xmit   /* data, length, max */
603                            )) {
604                 return False;
605         }
606
607         if (!cli_receive_trans(cli, SMBtrans2,
608                                &rparam, &param_len,
609                                &rdata, &data_len)) {
610                 return False;
611         }
612
613         if (!rdata || data_len < 68) {
614                 return False;
615         }
616
617         if (c_time) {
618                 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
619         }
620         if (a_time) {
621                 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
622         }
623         if (m_time) {
624                 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
625         }
626         if (w_time) {
627                 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
628         }
629         if (mode) {
630                 *mode = SVAL(rdata, 32);
631         }
632         if (size) {
633                 *size = IVAL(rdata, 48);
634         }
635         if (ino) {
636                 *ino = IVAL(rdata, 64);
637         }
638
639         SAFE_FREE(rdata);
640         SAFE_FREE(rparam);
641         return True;
642 }
643
644 /****************************************************************************
645 send a qfileinfo call
646 ****************************************************************************/
647 BOOL cli_qfileinfo_test(struct cli_state *cli, int fnum, int level, char **poutdata, uint32 *poutlen)
648 {
649         unsigned int data_len = 0;
650         unsigned int param_len = 0;
651         uint16 setup = TRANSACT2_QFILEINFO;
652         pstring param;
653         char *rparam=NULL, *rdata=NULL;
654
655         *poutdata = NULL;
656         *poutlen = 0;
657
658         /* if its a win95 server then fail this - win95 totally screws it
659            up */
660         if (cli->win95)
661                 return False;
662
663         param_len = 4;
664
665         memset(param, 0, param_len);
666         SSVAL(param, 0, fnum);
667         SSVAL(param, 2, level);
668
669         if (!cli_send_trans(cli, SMBtrans2, 
670                             NULL,                           /* name */
671                             -1, 0,                          /* fid, flags */
672                             &setup, 1, 0,                   /* setup, length, max */
673                             param, param_len, 2,            /* param, length, max */
674                             NULL, data_len, cli->max_xmit   /* data, length, max */
675                            )) {
676                 return False;
677         }
678
679         if (!cli_receive_trans(cli, SMBtrans2,
680                                &rparam, &param_len,
681                                &rdata, &data_len)) {
682                 return False;
683         }
684
685         *poutdata = memdup(rdata, data_len);
686         *poutlen = data_len;
687
688         SAFE_FREE(rdata);
689         SAFE_FREE(rparam);
690         return True;
691 }
692
693
694
695 /****************************************************************************
696 send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
697 ****************************************************************************/
698 NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstring alt_name)
699 {
700         unsigned int data_len = 0;
701         unsigned int param_len = 0;
702         uint16 setup = TRANSACT2_QPATHINFO;
703         pstring param;
704         char *rparam=NULL, *rdata=NULL;
705         int count=8;
706         char *p;
707         BOOL ret;
708         unsigned int len;
709
710         p = param;
711         memset(p, 0, 6);
712         SSVAL(p, 0, SMB_QUERY_FILE_ALT_NAME_INFO);
713         p += 6;
714         p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
715
716         param_len = PTR_DIFF(p, param);
717
718         do {
719                 ret = (cli_send_trans(cli, SMBtrans2, 
720                                       NULL,           /* Name */
721                                       -1, 0,          /* fid, flags */
722                                       &setup, 1, 0,   /* setup, length, max */
723                                       param, param_len, 10, /* param, length, max */
724                                       NULL, data_len, cli->max_xmit /* data, length, max */
725                                       ) &&
726                        cli_receive_trans(cli, SMBtrans2, 
727                                          &rparam, &param_len,
728                                          &rdata, &data_len));
729                 if (!ret && cli_is_dos_error(cli)) {
730                         /* we need to work around a Win95 bug - sometimes
731                            it gives ERRSRV/ERRerror temprarily */
732                         uint8 eclass;
733                         uint32 ecode;
734                         cli_dos_error(cli, &eclass, &ecode);
735                         if (eclass != ERRSRV || ecode != ERRerror) break;
736                         smb_msleep(100);
737                 }
738         } while (count-- && ret==False);
739
740         if (!ret || !rdata || data_len < 4) {
741                 return NT_STATUS_UNSUCCESSFUL;
742         }
743
744         len = IVAL(rdata, 0);
745
746         if (len > data_len - 4) {
747                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
748         }
749
750         clistr_pull(cli, alt_name, rdata+4, sizeof(fstring), len, STR_UNICODE);
751
752         SAFE_FREE(rdata);
753         SAFE_FREE(rparam);
754
755         return NT_STATUS_OK;
756 }