- add timeouts to connect() for password server connections. This
[samba.git] / source / client / clientutil.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB client
5    Copyright (C) Andrew Tridgell 1994-1995
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 #ifdef SYSLOG
23 #undef SYSLOG
24 #endif
25
26 #include "includes.h"
27
28 #ifndef REGISTER
29 #define REGISTER 0
30 #endif
31
32 pstring service="";
33 pstring desthost="";
34 extern pstring myname;
35 pstring password = "";
36 pstring username="";
37 pstring workgroup=WORKGROUP;
38 BOOL got_pass = False;
39 BOOL connect_as_printer = False;
40 BOOL connect_as_ipc = False;
41
42 char cryptkey[8];
43 BOOL doencrypt=False;
44
45 extern pstring user_socket_options;
46
47 /* 30 second timeout on most commands */
48 #define CLIENT_TIMEOUT (30*1000)
49 #define SHORT_TIMEOUT (5*1000)
50
51 int name_type = 0x20;
52
53 int max_protocol = PROTOCOL_NT1;
54
55 BOOL readbraw_supported = False;
56 BOOL writebraw_supported = False;
57
58 extern int DEBUGLEVEL;
59
60 int cnum = 0;
61 int pid = 0;
62 int gid = 0;
63 int uid = 0;
64 int mid = 0;
65
66 int max_xmit = BUFFER_SIZE;
67
68 BOOL have_ip = False;
69
70 struct in_addr dest_ip;
71
72 extern int Protocol;
73
74 extern int Client;
75
76
77 /****************************************************************************
78 setup basics in a outgoing packet
79 ****************************************************************************/
80 void cli_setup_pkt(char *outbuf)
81 {
82   SSVAL(outbuf,smb_pid,pid);
83   SSVAL(outbuf,smb_uid,uid);
84   SSVAL(outbuf,smb_mid,mid);
85   if (Protocol > PROTOCOL_CORE)
86     {
87       SCVAL(outbuf,smb_flg,0x8);
88       SSVAL(outbuf,smb_flg2,0x1);
89     }
90 }
91
92 /****************************************************************************
93   receive a SMB trans or trans2 response allocating the necessary memory
94   ****************************************************************************/
95 BOOL cli_receive_trans_response(char *inbuf,int trans,int *data_len,
96                                 int *param_len, char **data,char **param)
97 {
98   int total_data=0;
99   int total_param=0;
100   int this_data,this_param;
101
102   *data_len = *param_len = 0;
103
104   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
105   show_msg(inbuf);
106
107   /* sanity check */
108   if (CVAL(inbuf,smb_com) != trans)
109     {
110       DEBUG(0,("Expected %s response, got command 0x%02x\n",
111                trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
112       return(False);
113     }
114   if (CVAL(inbuf,smb_rcls) != 0)
115     return(False);
116
117   /* parse out the lengths */
118   total_data = SVAL(inbuf,smb_tdrcnt);
119   total_param = SVAL(inbuf,smb_tprcnt);
120
121   /* allocate it */
122   *data = Realloc(*data,total_data);
123   *param = Realloc(*param,total_param);
124
125   while (1)
126     {
127       this_data = SVAL(inbuf,smb_drcnt);
128       this_param = SVAL(inbuf,smb_prcnt);
129       if (this_data)
130         memcpy(*data + SVAL(inbuf,smb_drdisp),
131                smb_base(inbuf) + SVAL(inbuf,smb_droff),
132                this_data);
133       if (this_param)
134         memcpy(*param + SVAL(inbuf,smb_prdisp),
135                smb_base(inbuf) + SVAL(inbuf,smb_proff),
136                this_param);
137       *data_len += this_data;
138       *param_len += this_param;
139
140       /* parse out the total lengths again - they can shrink! */
141       total_data = SVAL(inbuf,smb_tdrcnt);
142       total_param = SVAL(inbuf,smb_tprcnt);
143
144       if (total_data <= *data_len && total_param <= *param_len)
145         break;
146
147       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
148       show_msg(inbuf);
149
150       /* sanity check */
151       if (CVAL(inbuf,smb_com) != trans)
152         {
153           DEBUG(0,("Expected %s response, got command 0x%02x\n",
154                    trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
155           return(False);
156         }
157       if (CVAL(inbuf,smb_rcls) != 0)
158           return(False);
159     }
160   
161   return(True);
162 }
163
164 /****************************************************************************
165 send a session request
166 ****************************************************************************/
167 BOOL cli_send_session_request(char *inbuf, char *outbuf)
168 {
169   fstring dest;
170   char *p;
171   int len = 4;
172   /* send a session request (RFC 8002) */
173
174   strcpy(dest,desthost);
175   p = strchr(dest,'.');
176   if (p) *p = 0;
177
178   /* put in the destination name */
179   p = outbuf+len;
180   name_mangle(dest,p,name_type);
181   len += name_len(p);
182
183   /* and my name */
184   p = outbuf+len;
185   name_mangle(myname,p,0);
186   len += name_len(p);
187
188   /* setup the packet length */
189   _smb_setlen(outbuf,len);
190   CVAL(outbuf,0) = 0x81;
191
192   send_smb(Client,outbuf);
193   DEBUG(5,("Sent session request\n"));
194
195   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
196
197   if (CVAL(inbuf,0) == 0x84) /* C. Hoch  9/14/95 Start */
198     {
199       /* For information, here is the response structure.
200        * We do the byte-twiddling to for portability.
201        struct RetargetResponse{
202        unsigned char type;
203        unsigned char flags;
204        int16 length;
205        int32 ip_addr;
206        int16 port;
207        };
208        */
209       extern int Client;
210       int port = (CVAL(inbuf,8)<<8)+CVAL(inbuf,9);
211       /* SESSION RETARGET */
212       putip((char *)&dest_ip,inbuf+4);
213
214       close_sockets();
215       Client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
216       if (Client == -1)
217         return False;
218
219       DEBUG(5,("Retargeted\n"));
220
221       set_socket_options(Client,user_socket_options);
222
223       /* Try again */
224       return cli_send_session_request(inbuf,outbuf);
225     } /* C. Hoch 9/14/95 End */
226
227
228   if (CVAL(inbuf,0) != 0x82)
229     {
230       int ecode = CVAL(inbuf,4);
231       DEBUG(0,("Session request failed (%d,%d) with myname=%s destname=%s\n",
232                CVAL(inbuf,0),ecode,myname,desthost));
233       switch (ecode)
234         {
235         case 0x80: 
236           DEBUG(0,("Not listening on called name\n")); 
237           DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
238           DEBUG(0,("You may find the -I option useful for this\n"));
239           break;
240         case 0x81: 
241           DEBUG(0,("Not listening for calling name\n")); 
242           DEBUG(0,("Try to connect as another name (instead of %s)\n",myname));
243           DEBUG(0,("You may find the -n option useful for this\n"));
244           break;
245         case 0x82: 
246           DEBUG(0,("Called name not present\n")); 
247           DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
248           DEBUG(0,("You may find the -I option useful for this\n"));
249           break;
250         case 0x83: 
251           DEBUG(0,("Called name present, but insufficient resources\n")); 
252           DEBUG(0,("Perhaps you should try again later?\n")); 
253           break;
254         default:
255           DEBUG(0,("Unspecified error 0x%X\n",ecode)); 
256           DEBUG(0,("Your server software is being unfriendly\n"));
257           break;          
258         }
259       return(False);
260     }
261   return(True);
262 }
263
264
265 static  struct {
266     int prot;
267     char *name;
268   }
269 prots[] = 
270     {
271       {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
272       {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
273       {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
274       {PROTOCOL_LANMAN1,"LANMAN1.0"},
275       {PROTOCOL_LANMAN2,"LM1.2X002"},
276       {PROTOCOL_LANMAN2,"Samba"},
277       {PROTOCOL_NT1,"NT LM 0.12"},
278       {PROTOCOL_NT1,"NT LANMAN 1.0"},
279       {-1,NULL}
280     };
281
282 /****************************************************************************
283 send a login command
284 ****************************************************************************/
285 BOOL cli_send_login(char *inbuf, char *outbuf, BOOL start_session, BOOL use_setup)
286 {
287   BOOL was_null = (!inbuf && !outbuf);
288   int sesskey=0;
289   time_t servertime = 0;
290   extern int serverzone;
291   int sec_mode=0;
292   int crypt_len;
293   int max_vcs=0;
294   char *pass = NULL;  
295   pstring dev;
296   char *p;
297   int numprots;
298
299   if (was_null)
300     {
301       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
302       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
303     }
304
305   strcpy(dev,"A:");
306   if (connect_as_printer)
307     strcpy(dev,"LPT1:");
308   if (connect_as_ipc)
309     strcpy(dev,"IPC");
310
311
312   if (start_session && !cli_send_session_request(inbuf,outbuf))
313     {
314       if (was_null)
315         {
316           free(inbuf);
317           free(outbuf);
318         }      
319       return(False);
320     }
321
322   bzero(outbuf,smb_size);
323
324   /* setup the protocol strings */
325   {
326     int plength;
327
328     for (plength=0,numprots=0;
329          prots[numprots].name && prots[numprots].prot<=max_protocol;
330          numprots++)
331       plength += strlen(prots[numprots].name)+2;
332     
333     set_message(outbuf,0,plength,True);
334
335     p = smb_buf(outbuf);
336     for (numprots=0;
337          prots[numprots].name && prots[numprots].prot<=max_protocol;
338          numprots++)
339       {
340         *p++ = 2;
341         strcpy(p,prots[numprots].name);
342         p += strlen(p) + 1;
343       }
344   }
345
346   CVAL(outbuf,smb_com) = SMBnegprot;
347   cli_setup_pkt(outbuf);
348
349   CVAL(smb_buf(outbuf),0) = 2;
350
351   send_smb(Client,outbuf);
352   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
353
354   show_msg(inbuf);
355
356   if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots))
357     {
358       DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n",
359             myname,desthost,smb_errstr(inbuf)));
360       if (was_null)
361         {
362           free(inbuf);
363           free(outbuf);
364         }
365       return(False);
366     }
367
368   Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
369
370
371   if (Protocol < PROTOCOL_NT1) {    
372     sec_mode = SVAL(inbuf,smb_vwv1);
373     max_xmit = SVAL(inbuf,smb_vwv2);
374     sesskey = IVAL(inbuf,smb_vwv6);
375     serverzone = SVALS(inbuf,smb_vwv10)*60;
376     /* this time is converted to GMT by make_unix_date */
377     servertime = make_unix_date(inbuf+smb_vwv8);
378     if (Protocol >= PROTOCOL_COREPLUS) {
379       readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0);
380       writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0);
381     }
382     crypt_len = smb_buflen(inbuf);
383     memcpy(cryptkey,smb_buf(inbuf),8);
384     DEBUG(5,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
385     max_vcs = SVAL(inbuf,smb_vwv4); 
386     DEBUG(5,("max vcs %d\n",max_vcs)); 
387     DEBUG(5,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
388   } else {
389     /* NT protocol */
390     sec_mode = CVAL(inbuf,smb_vwv1);
391     max_xmit = IVAL(inbuf,smb_vwv3+1);
392     sesskey = IVAL(inbuf,smb_vwv7+1);
393     serverzone = SVALS(inbuf,smb_vwv15+1)*60;
394     /* this time arrives in real GMT */
395     servertime = interpret_long_date(inbuf+smb_vwv11+1);
396     crypt_len = CVAL(inbuf,smb_vwv16+1);
397     memcpy(cryptkey,smb_buf(inbuf),8);
398     if (IVAL(inbuf,smb_vwv9+1) & 1)
399       readbraw_supported = writebraw_supported = True;      
400     DEBUG(5,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
401     max_vcs = SVAL(inbuf,smb_vwv2+1); 
402     DEBUG(5,("max vcs %d\n",max_vcs));
403     DEBUG(5,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
404     DEBUG(5,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
405   }
406
407   DEBUG(5,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
408   DEBUG(5,("max xmt %d\n",max_xmit));
409   DEBUG(5,("Got %d byte crypt key\n",crypt_len));
410   DEBUG(5,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name));
411
412   doencrypt = ((sec_mode & 2) != 0);
413
414   if (servertime) {
415     static BOOL done_time = False;
416     if (!done_time) {
417       DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
418                asctime(LocalTime(&servertime)),
419                -(double)(serverzone/3600.0)));
420       done_time = True;
421     }
422   }
423
424  get_pass:
425
426   if (got_pass)
427     pass = password;
428   else
429     pass = (char *)getpass("Password: ");
430
431   if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
432     {
433       fstring pword;
434       int passlen = strlen(pass)+1;
435       strcpy(pword,pass);      
436
437 #ifdef SMB_PASSWD
438       if (doencrypt && *pass) {
439         DEBUG(5,("Using encrypted passwords\n"));
440         passlen = 24;
441         SMBencrypt(pass,cryptkey,pword);
442       }
443 #else
444       doencrypt = False;
445 #endif
446
447       /* if in share level security then don't send a password now */
448       if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;} 
449
450       /* send a session setup command */
451       bzero(outbuf,smb_size);
452
453       if (Protocol < PROTOCOL_NT1) {
454         set_message(outbuf,10,1 + strlen(username) + passlen,True);
455         CVAL(outbuf,smb_com) = SMBsesssetupX;
456         cli_setup_pkt(outbuf);
457
458         CVAL(outbuf,smb_vwv0) = 0xFF;
459         SSVAL(outbuf,smb_vwv2,max_xmit);
460         SSVAL(outbuf,smb_vwv3,2);
461         SSVAL(outbuf,smb_vwv4,max_vcs-1);
462         SIVAL(outbuf,smb_vwv5,sesskey);
463         SSVAL(outbuf,smb_vwv7,passlen);
464         p = smb_buf(outbuf);
465         memcpy(p,pword,passlen);
466         p += passlen;
467         strcpy(p,username);
468       } else {
469         if (!doencrypt) passlen--;
470         /* for Win95 */
471         set_message(outbuf,13,0,True);
472         CVAL(outbuf,smb_com) = SMBsesssetupX;
473         cli_setup_pkt(outbuf);
474
475         CVAL(outbuf,smb_vwv0) = 0xFF;
476         SSVAL(outbuf,smb_vwv2,BUFFER_SIZE);
477         SSVAL(outbuf,smb_vwv3,2);
478         SSVAL(outbuf,smb_vwv4,getpid());
479         SIVAL(outbuf,smb_vwv5,sesskey);
480         SSVAL(outbuf,smb_vwv7,passlen);
481         SSVAL(outbuf,smb_vwv8,0);
482         p = smb_buf(outbuf);
483         memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
484         strcpy(p,username);p = skip_string(p,1);
485         strcpy(p,workgroup);p = skip_string(p,1);
486         strcpy(p,"Unix");p = skip_string(p,1);
487         strcpy(p,"Samba");p = skip_string(p,1);
488         set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
489       }
490
491       send_smb(Client,outbuf);
492       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
493
494       show_msg(inbuf);
495
496       if (CVAL(inbuf,smb_rcls) != 0)
497         {
498           if (! *pass &&
499               ((CVAL(inbuf,smb_rcls) == ERRDOS && 
500                 SVAL(inbuf,smb_err) == ERRnoaccess) ||
501                (CVAL(inbuf,smb_rcls) == ERRSRV && 
502                 SVAL(inbuf,smb_err) == ERRbadpw)))
503             {
504               got_pass = False;
505               DEBUG(5,("resending login\n"));
506               goto get_pass;
507             }
508               
509           DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s   %s\n",
510                 username,myname,desthost,smb_errstr(inbuf)));
511           DEBUG(0,("You might find the -U or -n options useful\n"));
512           DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n"));
513           DEBUG(0,("Some servers also insist on uppercase-only passwords\n"));
514           if (was_null)
515             {
516               free(inbuf);
517               free(outbuf);
518             }
519           return(False);
520         }
521
522       if (Protocol >= PROTOCOL_NT1) {
523         char *domain,*os,*lanman;
524         p = smb_buf(inbuf);
525         os = p;
526         lanman = skip_string(os,1);
527         domain = skip_string(lanman,1);
528         if (*domain || *os || *lanman)
529           DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman));
530       }
531
532       /* use the returned uid from now on */
533       if (SVAL(inbuf,smb_uid) != uid)
534         DEBUG(5,("Server gave us a UID of %d. We gave %d\n",
535               SVAL(inbuf,smb_uid),uid));
536       uid = SVAL(inbuf,smb_uid);
537     }
538
539   /* now we've got a connection - send a tcon message */
540   bzero(outbuf,smb_size);
541
542   if (strncmp(service,"\\\\",2) != 0)
543     {
544       DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n"));
545       DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n"));
546     }
547
548
549  again2:
550
551   {
552     int passlen = strlen(pass)+1;
553     fstring pword;
554     strcpy(pword,pass);
555
556 #ifdef SMB_PASSWD
557     if (doencrypt && *pass) {
558       passlen=24;
559       SMBencrypt(pass,cryptkey,pword);      
560     }
561 #endif
562
563     /* if in user level security then don't send a password now */
564     if ((sec_mode & 1)) {
565       strcpy(pword, ""); passlen=1; 
566     }
567
568     set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
569     CVAL(outbuf,smb_com) = SMBtconX;
570     cli_setup_pkt(outbuf);
571
572     SSVAL(outbuf,smb_vwv0,0xFF);
573     SSVAL(outbuf,smb_vwv3,passlen);
574
575     p = smb_buf(outbuf);
576     memcpy(p,pword,passlen);
577     p += passlen;
578     strcpy(p,service);
579     p = skip_string(p,1);
580     strcpy(p,dev);
581   }
582
583   send_smb(Client,outbuf);
584   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
585
586   /* trying again with a blank password */
587   if (CVAL(inbuf,smb_rcls) != 0 && 
588       (int)strlen(pass) > 0 && 
589       !doencrypt &&
590       Protocol >= PROTOCOL_LANMAN1)
591     {
592       DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
593       strcpy(pass,"");
594       goto again2;
595     }  
596
597   if (CVAL(inbuf,smb_rcls) != 0)
598     {
599       DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
600       DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
601       DEBUG(0,("Some servers insist that these be in uppercase\n"));
602       if (was_null)
603         {
604           free(inbuf);
605           free(outbuf);
606         }
607       return(False);
608     }
609   
610
611   max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
612   if (max_xmit <= 0)
613     max_xmit = BUFFER_SIZE - 4;
614
615   cnum = SVAL(inbuf,smb_tid);
616
617   DEBUG(5,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
618
619   if (was_null)
620     {
621       free(inbuf);
622       free(outbuf);
623     }
624   return True;
625 }
626
627
628 /****************************************************************************
629 send a logout command
630 ****************************************************************************/
631 void cli_send_logout(void)
632 {
633   pstring inbuf,outbuf;
634
635   bzero(outbuf,smb_size);
636   set_message(outbuf,0,0,True);
637   CVAL(outbuf,smb_com) = SMBtdis;
638   SSVAL(outbuf,smb_tid,cnum);
639   cli_setup_pkt(outbuf);
640
641   send_smb(Client,outbuf);
642   receive_smb(Client,inbuf,SHORT_TIMEOUT);
643
644   if (CVAL(inbuf,smb_rcls) != 0)
645     {
646       DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
647     }
648
649   
650 #ifdef STATS
651   stats_report();
652 #endif
653   exit(0);
654 }
655
656
657
658 /****************************************************************************
659 call a remote api
660 ****************************************************************************/
661 BOOL cli_call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt,
662               int *rdrcnt, char *param,char *data, char **rparam,char **rdata)
663 {
664   static char *inbuf=NULL;
665   static char *outbuf=NULL;
666
667   if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
668   if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
669
670   cli_send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
671                          data,param,NULL,
672                          drcnt,prcnt,0,
673                          mdrcnt,mprcnt,0);
674
675   return (cli_receive_trans_response(inbuf,SMBtrans,
676                                      rdrcnt,rprcnt,
677                                      rdata,rparam));
678 }
679
680 /****************************************************************************
681   send a SMB trans or trans2 request
682   ****************************************************************************/
683 BOOL cli_send_trans_request(char *outbuf, int trans, char *name, int fid, int flags,
684                         char *data,char *param,uint16 *setup, int ldata,int lparam,
685                         int lsetup,int mdata,int mparam,int msetup)
686 {
687   int i;
688   int this_ldata,this_lparam;
689   int tot_data=0,tot_param=0;
690   char *outdata,*outparam;
691   pstring inbuf;
692   char *p;
693
694   this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
695   this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
696
697   bzero(outbuf,smb_size);
698   set_message(outbuf,14+lsetup,0,True);
699   CVAL(outbuf,smb_com) = trans;
700   SSVAL(outbuf,smb_tid,cnum);
701   cli_setup_pkt(outbuf);
702
703   outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
704   outdata = outparam+this_lparam;
705
706   /* primary request */
707   SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
708   SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
709   SSVAL(outbuf,smb_mprcnt,mparam);      /* mprcnt */
710   SSVAL(outbuf,smb_mdrcnt,mdata);       /* mdrcnt */
711   SCVAL(outbuf,smb_msrcnt,msetup);      /* msrcnt */
712   SSVAL(outbuf,smb_flags,flags);        /* flags */
713   SIVAL(outbuf,smb_timeout,0);          /* timeout */
714   SSVAL(outbuf,smb_pscnt,this_lparam);  /* pscnt */
715   SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */
716   SSVAL(outbuf,smb_dscnt,this_ldata);   /* dscnt */
717   SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */
718   SCVAL(outbuf,smb_suwcnt,lsetup);      /* suwcnt */
719   for (i=0;i<lsetup;i++)                /* setup[] */
720     SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
721   p = smb_buf(outbuf);
722   if (trans==SMBtrans)
723     strcpy(p,name);                     /* name[] */
724   else
725     {
726       *p++ = 0;                         /* put in a null smb_name */
727       *p++ = 'D'; *p++ = ' ';           /* this was added because OS/2 does it */
728     }
729   if (this_lparam)                      /* param[] */
730     memcpy(outparam,param,this_lparam);
731   if (this_ldata)                       /* data[] */
732     memcpy(outdata,data,this_ldata);
733   set_message(outbuf,14+lsetup,         /* wcnt, bcc */
734               PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
735
736   show_msg(outbuf);
737   send_smb(Client,outbuf);
738
739   if (this_ldata < ldata || this_lparam < lparam)
740     {
741       /* receive interim response */
742       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
743         {
744           DEBUG(0,("%s request failed (%s)\n",
745                    trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf)));
746           return(False);
747         }      
748
749       tot_data = this_ldata;
750       tot_param = this_lparam;
751
752       while (tot_data < ldata || tot_param < lparam)
753     {
754           this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */
755           this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam));
756
757           set_message(outbuf,trans==SMBtrans?8:9,0,True);
758           CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
759
760           outparam = smb_buf(outbuf);
761           outdata = outparam+this_lparam;
762
763           /* secondary request */
764           SSVAL(outbuf,smb_tpscnt,lparam);      /* tpscnt */
765           SSVAL(outbuf,smb_tdscnt,ldata);       /* tdscnt */
766           SSVAL(outbuf,smb_spscnt,this_lparam); /* pscnt */
767           SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */
768           SSVAL(outbuf,smb_spsdisp,tot_param);  /* psdisp */
769           SSVAL(outbuf,smb_sdscnt,this_ldata);  /* dscnt */
770           SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */
771           SSVAL(outbuf,smb_sdsdisp,tot_data);   /* dsdisp */
772           if (trans==SMBtrans2)
773             SSVAL(outbuf,smb_sfid,fid);         /* fid */
774           if (this_lparam)                      /* param[] */
775             memcpy(outparam,param,this_lparam);
776           if (this_ldata)                       /* data[] */
777             memcpy(outdata,data,this_ldata);
778           set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
779                       PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
780
781           show_msg(outbuf);
782           send_smb(Client,outbuf);
783
784           tot_data += this_ldata;
785           tot_param += this_lparam;
786         }
787     }
788
789     return(True);
790 }
791
792
793 /****************************************************************************
794 open the client sockets
795 ****************************************************************************/
796 BOOL cli_open_sockets(int port)
797 {
798   static int last_port;
799   char *host;
800   pstring service2;
801   extern int Client;
802
803   if (port == 0) port=last_port;
804   last_port=port;
805
806   strupper(service);
807
808   if (*desthost)
809     {
810       host = desthost;
811     }
812   else
813     {
814       strcpy(service2,service);
815       host = strtok(service2,"\\/");
816       strcpy(desthost,host);
817     }
818
819   DEBUG(5,("Opening sockets\n"));
820
821   if (*myname == 0)
822     get_myname(myname,NULL);
823   strupper(myname);
824
825   if (!have_ip)
826     {
827       struct hostent *hp;
828
829       if ((hp = Get_Hostbyname(host)) == 0) 
830         {
831           DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
832           return False;
833         }
834
835       putip((char *)&dest_ip,(char *)hp->h_addr);
836     }
837
838   Client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
839   if (Client == -1)
840     return False;
841
842   DEBUG(5,("Connected\n"));
843
844   set_socket_options(Client,user_socket_options);  
845
846   return True;
847 }
848
849 /****************************************************************************
850 close and open the connection again
851 ****************************************************************************/
852 BOOL cli_reopen_connection(char *inbuf,char *outbuf)
853 {
854   static int open_count=0;
855
856   open_count++;
857
858   if (open_count>5) return(False);
859
860   DEBUG(1,("Trying to re-open connection\n"));
861
862   set_message(outbuf,0,0,True);
863   SCVAL(outbuf,smb_com,SMBtdis);
864   SSVAL(outbuf,smb_tid,cnum);
865   cli_setup_pkt(outbuf);
866
867   send_smb(Client,outbuf);
868   receive_smb(Client,inbuf,SHORT_TIMEOUT);
869
870   close_sockets();
871   if (!cli_open_sockets(0)) return(False);
872
873   return(cli_send_login(inbuf,outbuf,True,True));
874 }
875
876 /* error code stuff - put together by Merik Karman
877    merik@blackadder.dsh.oz.au */
878
879 typedef struct
880 {
881   char *name;
882   int code;
883   char *message;
884 } err_code_struct;
885
886 /* Dos Error Messages */
887 err_code_struct dos_msgs[] = {
888   {"ERRbadfunc",1,"Invalid function."},
889   {"ERRbadfile",2,"File not found."},
890   {"ERRbadpath",3,"Directory invalid."},
891   {"ERRnofids",4,"No file descriptors available"},
892   {"ERRnoaccess",5,"Access denied."},
893   {"ERRbadfid",6,"Invalid file handle."},
894   {"ERRbadmcb",7,"Memory control blocks destroyed."},
895   {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
896   {"ERRbadmem",9,"Invalid memory block address."},
897   {"ERRbadenv",10,"Invalid environment."},
898   {"ERRbadformat",11,"Invalid format."},
899   {"ERRbadaccess",12,"Invalid open mode."},
900   {"ERRbaddata",13,"Invalid data."},
901   {"ERR",14,"reserved."},
902   {"ERRbaddrive",15,"Invalid drive specified."},
903   {"ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
904   {"ERRdiffdevice",17,"Not same device."},
905   {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
906   {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
907   {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an  invalid mode,  or an Unlock requested attempted to remove a lock held by another process."},
908   {"ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
909   {"ERRbadpipe",230,"Pipe invalid."},
910   {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
911   {"ERRpipeclosing",232,"Pipe close in progress."},
912   {"ERRnotconnected",233,"No process on other end of pipe."},
913   {"ERRmoredata",234,"There is more data to be returned."},
914   {NULL,-1,NULL}};
915
916 /* Server Error Messages */
917 err_code_struct server_msgs[] = {
918   {"ERRerror",1,"Non-specific error code."},
919   {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
920   {"ERRbadtype",3,"reserved."},
921   {"ERRaccess",4,"The requester does not have  the  necessary  access  rights  within  the specified  context for the requested function. The context is defined by the TID or the UID."},
922   {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
923   {"ERRinvnetname",6,"Invalid network name in tree connect."},
924   {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
925   {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
926   {"ERRqtoobig",50,"Print queue full -- no space."},
927   {"ERRqeof",51,"EOF on print queue dump."},
928   {"ERRinvpfid",52,"Invalid print file FID."},
929   {"ERRsmbcmd",64,"The server did not recognize the command received."},
930   {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
931   {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
932   {"ERRreserved",68,"reserved."},
933   {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
934   {"ERRreserved",70,"reserved."},
935   {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
936   {"ERRpaused",81,"Server is paused."},
937   {"ERRmsgoff",82,"Not receiving messages."},
938   {"ERRnoroom",83,"No room to buffer message."},
939   {"ERRrmuns",87,"Too many remote user names."},
940   {"ERRtimeout",88,"Operation timed out."},
941   {"ERRnoresource",89,"No resources currently available for request."},
942   {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
943   {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
944   {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
945   {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
946   {"ERRcontmpx",252,"Continue in MPX mode."},
947   {"ERRreserved",253,"reserved."},
948   {"ERRreserved",254,"reserved."},
949   {"ERRnosupport",0xFFFF,"Function not supported."},
950   {NULL,-1,NULL}};
951
952 /* Hard Error Messages */
953 err_code_struct hard_msgs[] = {
954   {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
955   {"ERRbadunit",20,"Unknown unit."},
956   {"ERRnotready",21,"Drive not ready."},
957   {"ERRbadcmd",22,"Unknown command."},
958   {"ERRdata",23,"Data error (CRC)."},
959   {"ERRbadreq",24,"Bad request structure length."},
960   {"ERRseek",25 ,"Seek error."},
961   {"ERRbadmedia",26,"Unknown media type."},
962   {"ERRbadsector",27,"Sector not found."},
963   {"ERRnopaper",28,"Printer out of paper."},
964   {"ERRwrite",29,"Write fault."},
965   {"ERRread",30,"Read fault."},
966   {"ERRgeneral",31,"General failure."},
967   {"ERRbadshare",32,"A open conflicts with an existing open."},
968   {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
969   {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
970   {"ERRFCBUnavail",35,"No FCBs are available to process request."},
971   {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
972   {NULL,-1,NULL}};
973
974
975 struct
976 {
977   int code;
978   char *class;
979   err_code_struct *err_msgs;
980 } err_classes[] = { 
981   {0,"SUCCESS",NULL},
982   {0x01,"ERRDOS",dos_msgs},
983   {0x02,"ERRSRV",server_msgs},
984   {0x03,"ERRHRD",hard_msgs},
985   {0x04,"ERRXOS",NULL},
986   {0xE1,"ERRRMX1",NULL},
987   {0xE2,"ERRRMX2",NULL},
988   {0xE3,"ERRRMX3",NULL},
989   {0xFF,"ERRCMD",NULL},
990   {-1,NULL,NULL}};
991
992
993 /****************************************************************************
994 return a SMB error string from a SMB buffer
995 ****************************************************************************/
996 char *smb_errstr(char *inbuf)
997 {
998   static pstring ret;
999   int class = CVAL(inbuf,smb_rcls);
1000   int num = SVAL(inbuf,smb_err);
1001   int i,j;
1002
1003   for (i=0;err_classes[i].class;i++)
1004     if (err_classes[i].code == class)
1005       {
1006         if (err_classes[i].err_msgs)
1007           {
1008             err_code_struct *err = err_classes[i].err_msgs;
1009             for (j=0;err[j].name;j++)
1010               if (num == err[j].code)
1011                 {
1012                   if (DEBUGLEVEL > 0)
1013                     sprintf(ret,"%s - %s (%s)",err_classes[i].class,
1014                             err[j].name,err[j].message);
1015                   else
1016                     sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
1017                   return ret;
1018                 }
1019           }
1020
1021         sprintf(ret,"%s - %d",err_classes[i].class,num);
1022         return ret;
1023       }
1024   
1025   sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
1026   return(ret);
1027 }