better error reporting for servers that don't do port 445
[ira/wip.git] / source / libsmb / cliconnect.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    client connect/disconnect routines
5    Copyright (C) Andrew Tridgell 1994-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #define NO_SYSLOG
23
24 #include "includes.h"
25
26
27 static  struct {
28     int prot;
29     const char *name;
30   }
31 prots[] = 
32     {
33       {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
34       {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
35       {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
36       {PROTOCOL_LANMAN1,"LANMAN1.0"},
37       {PROTOCOL_LANMAN2,"LM1.2X002"},
38       {PROTOCOL_LANMAN2,"Samba"},
39       {PROTOCOL_NT1,"NT LANMAN 1.0"},
40       {PROTOCOL_NT1,"NT LM 0.12"},
41       {-1,NULL}
42     };
43
44
45 /****************************************************************************
46  Send a session setup. The username and workgroup is in UNIX character
47  format and must be converted to DOS codepage format before sending. If the
48  password is in plaintext, the same should be done.
49 ****************************************************************************/
50
51 BOOL cli_session_setup(struct cli_state *cli, 
52                        char *user, 
53                        char *pass, int passlen,
54                        char *ntpass, int ntpasslen,
55                        char *workgroup)
56 {
57         char *p;
58         fstring pword, ntpword;
59         fstring user2;
60
61         /* allow for workgroups as part of the username */
62         fstrcpy(user2, user);
63         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
64                 *p = 0;
65                 user = p+1;
66                 workgroup = user2;
67         }
68
69         if (cli->protocol < PROTOCOL_LANMAN1)
70                 return True;
71
72         if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
73                 return False;
74         }
75
76         if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
77                 /* Null session connect. */
78                 pword[0] = '\0';
79                 ntpword[0] = '\0';
80         } else {
81                 if ((cli->sec_mode & 2) && passlen != 24) {
82                         /*
83                          * Encrypted mode needed, and non encrypted password supplied.
84                          */
85                         passlen = 24;
86                         ntpasslen = 24;
87                         clistr_push(cli, pword, pass, -1, STR_TERMINATE);
88                         fstrcpy(ntpword, ntpass);;
89                         SMBencrypt((uchar *)pword,(uchar *)cli->cryptkey,(uchar *)pword);
90                         SMBNTencrypt((uchar *)ntpword,(uchar *)cli->cryptkey,(uchar *)ntpword);
91                 } else if ((cli->sec_mode & 2) && passlen == 24) {
92                         /*
93                          * Encrypted mode needed, and encrypted password supplied.
94                          */
95                         memcpy(pword, pass, passlen);
96                         if(ntpasslen == 24) {
97                                 memcpy(ntpword, ntpass, ntpasslen);
98                         } else {
99                                 fstrcpy(ntpword, "");
100                                 ntpasslen = 0;
101                         }
102                 } else {
103                         /*
104                          * Plaintext mode needed, assume plaintext supplied.
105                          */
106                         passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
107                         fstrcpy(ntpword, "");
108                         ntpasslen = 0;
109                 }
110         }
111
112         /* if in share level security then don't send a password now */
113         if (!(cli->sec_mode & 1)) {
114                 fstrcpy(pword, "");
115                 passlen=1;
116                 fstrcpy(ntpword, "");
117                 ntpasslen=1;
118         } 
119
120         /* send a session setup command */
121         memset(cli->outbuf,'\0',smb_size);
122
123         if (cli->protocol < PROTOCOL_NT1)
124         {
125                 set_message(cli->outbuf,10, 0, True);
126                 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
127                 cli_setup_packet(cli);
128
129                 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
130                 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
131                 SSVAL(cli->outbuf,smb_vwv3,2);
132                 SSVAL(cli->outbuf,smb_vwv4,1);
133                 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
134                 SSVAL(cli->outbuf,smb_vwv7,passlen);
135                 p = smb_buf(cli->outbuf);
136                 memcpy(p,pword,passlen);
137                 p += passlen;
138                 p += clistr_push(cli, p, user, -1, STR_UPPER|STR_TERMINATE);
139                 cli_setup_bcc(cli, p);
140         }
141         else
142         {
143                 uint32 capabilities;
144
145                 capabilities = CAP_NT_SMBS;
146
147                 /* Set the CLI_FORCE_DOSERR environment variable to test
148                    client routines using DOS errors instead of STATUS32
149                    ones.  This intended only as a temporary hack. */
150
151                 if (!getenv("CLI_FORCE_DOSERR")) {
152                         capabilities |= CAP_STATUS32;
153                 }
154
155                 if (cli->use_level_II_oplocks) {
156                         capabilities |= CAP_LEVEL_II_OPLOCKS;
157                 }
158                 if (cli->capabilities & CAP_UNICODE) {
159                         capabilities |= CAP_UNICODE;
160                 }
161                 set_message(cli->outbuf,13,0,True);
162                 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
163                 cli_setup_packet(cli);
164                 
165                 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
166                 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
167                 SSVAL(cli->outbuf,smb_vwv3,2);
168                 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
169                 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
170                 SSVAL(cli->outbuf,smb_vwv7,passlen);
171                 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
172                 SIVAL(cli->outbuf,smb_vwv11,capabilities);
173                 p = smb_buf(cli->outbuf);
174                 memcpy(p,pword,passlen); 
175                 p += SVAL(cli->outbuf,smb_vwv7);
176                 memcpy(p,ntpword,ntpasslen); 
177                 p += SVAL(cli->outbuf,smb_vwv8);
178                 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
179                 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
180                 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
181                 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
182                 cli_setup_bcc(cli, p);
183         }
184
185       cli_send_smb(cli);
186       if (!cli_receive_smb(cli))
187               return False;
188
189       show_msg(cli->inbuf);
190
191       if (CVAL(cli->inbuf,smb_rcls) != 0) {
192               return False;
193       }
194
195       /* use the returned vuid from now on */
196       cli->vuid = SVAL(cli->inbuf,smb_uid);
197
198       if (cli->protocol >= PROTOCOL_NT1) {
199               /*
200                * Save off some of the connected server
201                * info.
202                */
203               char *q = smb_buf(cli->inbuf);
204               q += clistr_pull(cli, cli->server_os, q, sizeof(fstring), -1, STR_TERMINATE);
205               q += clistr_pull(cli, cli->server_type, q, sizeof(fstring), -1, STR_TERMINATE);
206               q += clistr_pull(cli, cli->server_domain, q, sizeof(fstring), -1, STR_TERMINATE);
207       }
208
209       fstrcpy(cli->user_name, user);
210
211       return True;
212 }
213
214 /****************************************************************************
215  Send a uloggoff.
216 *****************************************************************************/
217
218 BOOL cli_ulogoff(struct cli_state *cli)
219 {
220         memset(cli->outbuf,'\0',smb_size);
221         set_message(cli->outbuf,2,0,True);
222         CVAL(cli->outbuf,smb_com) = SMBulogoffX;
223         cli_setup_packet(cli);
224         SSVAL(cli->outbuf,smb_vwv0,0xFF);
225         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
226
227         cli_send_smb(cli);
228         if (!cli_receive_smb(cli))
229                 return False;
230
231         return CVAL(cli->inbuf,smb_rcls) == 0;
232 }
233
234 /****************************************************************************
235 send a tconX
236 ****************************************************************************/
237 BOOL cli_send_tconX(struct cli_state *cli, 
238                     const char *share, const char *dev, const char *pass, int passlen)
239 {
240         fstring fullshare, pword, dos_pword;
241         char *p;
242         memset(cli->outbuf,'\0',smb_size);
243         memset(cli->inbuf,'\0',smb_size);
244
245         fstrcpy(cli->share, share);
246
247         /* in user level security don't send a password now */
248         if (cli->sec_mode & 1) {
249                 passlen = 1;
250                 pass = "";
251         }
252
253         if ((cli->sec_mode & 2) && *pass && passlen != 24) {
254                 /*
255                  * Non-encrypted passwords - convert to DOS codepage before encryption.
256                  */
257                 passlen = 24;
258                 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
259                 
260                 SMBencrypt((uchar *)dos_pword,(uchar *)cli->cryptkey,(uchar *)pword);
261         } else {
262                 if((cli->sec_mode & 3) == 0) {
263                         /*
264                          * Non-encrypted passwords - convert to DOS codepage before using.
265                          */
266                         passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
267                 } else {
268                         memcpy(pword, pass, passlen);
269                 }
270         }
271
272         if (cli->port == 445) {
273                 slprintf(fullshare, sizeof(fullshare)-1,
274                          "%s", share);
275         } else {
276                 slprintf(fullshare, sizeof(fullshare)-1,
277                          "\\\\%s\\%s", "foo", share);
278         }
279
280         set_message(cli->outbuf,4, 0, True);
281         CVAL(cli->outbuf,smb_com) = SMBtconX;
282         cli_setup_packet(cli);
283
284         SSVAL(cli->outbuf,smb_vwv0,0xFF);
285         SSVAL(cli->outbuf,smb_vwv3,passlen);
286
287         p = smb_buf(cli->outbuf);
288         memcpy(p,pword,passlen);
289         p += passlen;
290         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
291         fstrcpy(p, dev); p += strlen(dev)+1;
292
293         cli_setup_bcc(cli, p);
294
295         SCVAL(cli->inbuf,smb_rcls, 1);
296
297         cli_send_smb(cli);
298         if (!cli_receive_smb(cli))
299                 return False;
300
301         if (CVAL(cli->inbuf,smb_rcls) != 0) {
302                 return False;
303         }
304
305         fstrcpy(cli->dev, "A:");
306
307         if (cli->protocol >= PROTOCOL_NT1) {
308                 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE);
309         }
310
311         if (strcasecmp(share,"IPC$")==0) {
312                 fstrcpy(cli->dev, "IPC");
313         }
314
315         /* only grab the device if we have a recent protocol level */
316         if (cli->protocol >= PROTOCOL_NT1 &&
317             smb_buflen(cli->inbuf) == 3) {
318                 /* almost certainly win95 - enable bug fixes */
319                 cli->win95 = True;
320         }
321
322         cli->cnum = SVAL(cli->inbuf,smb_tid);
323         return True;
324 }
325
326
327 /****************************************************************************
328 send a tree disconnect
329 ****************************************************************************/
330 BOOL cli_tdis(struct cli_state *cli)
331 {
332         memset(cli->outbuf,'\0',smb_size);
333         set_message(cli->outbuf,0,0,True);
334         CVAL(cli->outbuf,smb_com) = SMBtdis;
335         SSVAL(cli->outbuf,smb_tid,cli->cnum);
336         cli_setup_packet(cli);
337         
338         cli_send_smb(cli);
339         if (!cli_receive_smb(cli))
340                 return False;
341         
342         return CVAL(cli->inbuf,smb_rcls) == 0;
343 }
344
345
346 /****************************************************************************
347 send a negprot command
348 ****************************************************************************/
349 void cli_negprot_send(struct cli_state *cli)
350 {
351         char *p;
352         int numprots;
353
354         memset(cli->outbuf,'\0',smb_size);
355
356         /* setup the protocol strings */
357         set_message(cli->outbuf,0,0,True);
358
359         p = smb_buf(cli->outbuf);
360         for (numprots=0;
361              prots[numprots].name && prots[numprots].prot<=cli->protocol;
362              numprots++) {
363                 *p++ = 2;
364                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
365         }
366
367         CVAL(cli->outbuf,smb_com) = SMBnegprot;
368         cli_setup_bcc(cli, p);
369         cli_setup_packet(cli);
370
371         CVAL(smb_buf(cli->outbuf),0) = 2;
372
373         cli_send_smb(cli);
374 }
375
376
377 /****************************************************************************
378 send a negprot command
379 ****************************************************************************/
380 BOOL cli_negprot(struct cli_state *cli)
381 {
382         char *p;
383         int numprots;
384         int plength;
385
386         memset(cli->outbuf,'\0',smb_size);
387
388         /* setup the protocol strings */
389         for (plength=0,numprots=0;
390              prots[numprots].name && prots[numprots].prot<=cli->protocol;
391              numprots++)
392                 plength += strlen(prots[numprots].name)+2;
393     
394         set_message(cli->outbuf,0,plength,True);
395
396         p = smb_buf(cli->outbuf);
397         for (numprots=0;
398              prots[numprots].name && prots[numprots].prot<=cli->protocol;
399              numprots++) {
400                 *p++ = 2;
401                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
402         }
403
404         CVAL(cli->outbuf,smb_com) = SMBnegprot;
405         cli_setup_packet(cli);
406
407         CVAL(smb_buf(cli->outbuf),0) = 2;
408
409         cli_send_smb(cli);
410         if (!cli_receive_smb(cli))
411                 return False;
412
413         show_msg(cli->inbuf);
414
415         if (CVAL(cli->inbuf,smb_rcls) != 0 || 
416             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
417                 return(False);
418         }
419
420         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
421
422         if (cli->protocol >= PROTOCOL_NT1) {    
423                 /* NT protocol */
424                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
425                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
426                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
427                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
428                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
429                 cli->serverzone *= 60;
430                 /* this time arrives in real GMT */
431                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
432                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
433                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
434                 if (cli->capabilities & CAP_RAW_MODE) {
435                         cli->readbraw_supported = True;
436                         cli->writebraw_supported = True;      
437                 }
438                 /* work out if they sent us a workgroup */
439                 if (smb_buflen(cli->inbuf) > 8) {
440                         clistr_pull(cli, cli->server_domain, 
441                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
442                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
443                 }
444         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
445                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
446                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
447                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
448                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
449                 cli->serverzone *= 60;
450                 /* this time is converted to GMT by make_unix_date */
451                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
452                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
453                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
454                 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
455         } else {
456                 /* the old core protocol */
457                 cli->sec_mode = 0;
458                 cli->serverzone = TimeDiff(time(NULL));
459         }
460
461         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
462
463         /* a way to force ascii SMB */
464         if (getenv("CLI_FORCE_ASCII")) {
465                 cli->capabilities &= ~CAP_UNICODE;
466         }
467
468         return True;
469 }
470
471
472 /****************************************************************************
473   send a session request.  see rfc1002.txt 4.3 and 4.3.2
474 ****************************************************************************/
475 BOOL cli_session_request(struct cli_state *cli,
476                          struct nmb_name *calling, struct nmb_name *called)
477 {
478         char *p;
479         int len = 4;
480         extern pstring user_socket_options;
481
482         /* 445 doesn't have session request */
483         if (cli->port == 445) return True;
484
485         /* send a session request (RFC 1002) */
486
487         memcpy(&(cli->calling), calling, sizeof(*calling));
488         memcpy(&(cli->called ), called , sizeof(*called ));
489   
490         /* put in the destination name */
491         p = cli->outbuf+len;
492         name_mangle(cli->called .name, p, cli->called .name_type);
493         len += name_len(p);
494
495         /* and my name */
496         p = cli->outbuf+len;
497         name_mangle(cli->calling.name, p, cli->calling.name_type);
498         len += name_len(p);
499
500         /* setup the packet length */
501         _smb_setlen(cli->outbuf,len);
502         CVAL(cli->outbuf,0) = 0x81;
503
504 #ifdef WITH_SSL
505 retry:
506 #endif /* WITH_SSL */
507
508         cli_send_smb(cli);
509         DEBUG(5,("Sent session request\n"));
510
511         if (!cli_receive_smb(cli))
512                 return False;
513
514         if (CVAL(cli->inbuf,0) == 0x84) {
515                 /* C. Hoch  9/14/95 Start */
516                 /* For information, here is the response structure.
517                  * We do the byte-twiddling to for portability.
518                 struct RetargetResponse{
519                 unsigned char type;
520                 unsigned char flags;
521                 int16 length;
522                 int32 ip_addr;
523                 int16 port;
524                 };
525                 */
526                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
527                 /* SESSION RETARGET */
528                 putip((char *)&cli->dest_ip,cli->inbuf+4);
529
530                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
531                 if (cli->fd == -1)
532                         return False;
533
534                 DEBUG(3,("Retargeted\n"));
535
536                 set_socket_options(cli->fd,user_socket_options);
537
538                 /* Try again */
539                 {
540                         static int depth;
541                         BOOL ret;
542                         if (depth > 4) {
543                                 DEBUG(0,("Retarget recursion - failing\n"));
544                                 return False;
545                         }
546                         depth++;
547                         ret = cli_session_request(cli, calling, called);
548                         depth--;
549                         return ret;
550                 }
551         } /* C. Hoch 9/14/95 End */
552
553 #ifdef WITH_SSL
554     if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
555         if (!sslutil_fd_is_ssl(cli->fd)){
556             if (sslutil_connect(cli->fd) == 0)
557                 goto retry;
558         }
559     }
560 #endif /* WITH_SSL */
561
562         if (CVAL(cli->inbuf,0) != 0x82) {
563                 /* This is the wrong place to put the error... JRA. */
564                 cli->rap_error = CVAL(cli->inbuf,4);
565                 return False;
566         }
567         return(True);
568 }
569
570 /****************************************************************************
571 open the client sockets
572 ****************************************************************************/
573 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
574 {
575         extern struct in_addr ipzero;
576         extern pstring user_socket_options;
577
578         fstrcpy(cli->desthost, host);
579         
580         if (!ip || ip_equal(*ip, ipzero)) {
581                 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
582                         return False;
583                 }
584                 if (ip) *ip = cli->dest_ip;
585         } else {
586                 cli->dest_ip = *ip;
587         }
588
589         if (getenv("LIBSMB_PROG")) {
590                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
591         } else {
592                 /* try 445 first, then 139 */
593                 int port = cli->port?cli->port:445;
594                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
595                                           port, cli->timeout);
596                 if (cli->fd == -1 && cli->port == 0) {
597                         port = 139;
598                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
599                                                   port, cli->timeout);
600                 }
601                 if (cli->fd != -1) cli->port = port;
602         }
603         if (cli->fd == -1) {
604                 DEBUG(1,("Error connecting to %s (%s)\n",
605                          inet_ntoa(*ip),strerror(errno)));
606                 return False;
607         }
608
609         set_socket_options(cli->fd,user_socket_options);
610
611         return True;
612 }
613
614 /****************************************************************************
615 re-establishes a connection
616 ****************************************************************************/
617 BOOL cli_reestablish_connection(struct cli_state *cli)
618 {
619         struct nmb_name calling;
620         struct nmb_name called;
621         fstring dest_host;
622         fstring share;
623         fstring dev;
624         BOOL do_tcon = False;
625         int oldfd = cli->fd;
626
627         if (!cli->initialised || cli->fd == -1)
628         {
629                 DEBUG(3,("cli_reestablish_connection: not connected\n"));
630                 return False;
631         }
632
633         /* copy the parameters necessary to re-establish the connection */
634
635         if (cli->cnum != 0)
636         {
637                 fstrcpy(share, cli->share);
638                 fstrcpy(dev  , cli->dev);
639                 do_tcon = True;
640         }
641
642         memcpy(&called , &(cli->called ), sizeof(called ));
643         memcpy(&calling, &(cli->calling), sizeof(calling));
644         fstrcpy(dest_host, cli->full_dest_host_name);
645
646         DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
647                  nmb_namestr(&calling), nmb_namestr(&called), 
648                  inet_ntoa(cli->dest_ip),
649                  cli->user_name, cli->domain));
650
651         cli->fd = -1;
652
653         if (cli_establish_connection(cli,
654                                      dest_host, &cli->dest_ip,
655                                      &calling, &called,
656                                      share, dev, False, do_tcon)) {
657                 if ((cli->fd != oldfd) && (oldfd != -1)) {
658                         close( oldfd );
659                 }
660                 return True;
661         }
662         return False;
663 }
664
665 /****************************************************************************
666 establishes a connection right up to doing tconX, reading in a password.
667 ****************************************************************************/
668 BOOL cli_establish_connection(struct cli_state *cli, 
669                                 char *dest_host, struct in_addr *dest_ip,
670                                 struct nmb_name *calling, struct nmb_name *called,
671                                 char *service, char *service_type,
672                                 BOOL do_shutdown, BOOL do_tcon)
673 {
674         DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
675                           nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
676                       cli->user_name, cli->domain));
677
678         /* establish connection */
679
680         if ((!cli->initialised))
681         {
682                 return False;
683         }
684
685         if (cli->fd == -1)
686         {
687                 if (!cli_connect(cli, dest_host, dest_ip))
688                 {
689                         DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
690                                           nmb_namestr(calling), inet_ntoa(*dest_ip)));
691                         return False;
692                 }
693         }
694
695         if (!cli_session_request(cli, calling, called))
696         {
697                 DEBUG(1,("failed session request\n"));
698                 if (do_shutdown)
699                         cli_shutdown(cli);
700                 return False;
701         }
702
703         if (!cli_negprot(cli))
704         {
705                 DEBUG(1,("failed negprot\n"));
706                 if (do_shutdown)
707                         cli_shutdown(cli);
708                 return False;
709         }
710
711         if (cli->pwd.cleartext || cli->pwd.null_pwd)
712         {
713                 fstring passwd;
714                 int pass_len;
715
716                 if (cli->pwd.null_pwd)
717                 {
718                         /* attempt null session */
719                         passwd[0] = 0;
720                         pass_len = 1;
721                 }
722                 else
723                 {
724                         /* attempt clear-text session */
725                         pwd_get_cleartext(&(cli->pwd), passwd);
726                         pass_len = strlen(passwd);
727                 }
728
729                 /* attempt clear-text session */
730                 if (!cli_session_setup(cli, cli->user_name,
731                                passwd, pass_len,
732                                NULL, 0,
733                                cli->domain))
734                 {
735                         DEBUG(1,("failed session setup\n"));
736                         if (do_shutdown)
737                         {
738                                 cli_shutdown(cli);
739                         }
740                         return False;
741                 }
742                 if (do_tcon)
743                 {
744                         if (!cli_send_tconX(cli, service, service_type,
745                                             (char*)passwd, strlen(passwd)))
746                         {
747                                 DEBUG(1,("failed tcon_X\n"));
748                                 if (do_shutdown)
749                                 {
750                                         cli_shutdown(cli);
751                                 }
752                                 return False;
753                         }
754                 }
755         }
756         else
757         {
758                 /* attempt encrypted session */
759                 unsigned char nt_sess_pwd[24];
760                 unsigned char lm_sess_pwd[24];
761
762                 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
763                 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
764                 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
765
766                 /* attempt encrypted session */
767                 if (!cli_session_setup(cli, cli->user_name,
768                                (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
769                                (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
770                                cli->domain))
771                 {
772                         DEBUG(1,("failed session setup\n"));
773                         if (do_shutdown)
774                               cli_shutdown(cli);
775                         return False;
776                 }
777
778                 DEBUG(1,("session setup ok\n"));
779     
780                 if (*cli->server_domain || *cli->server_os || *cli->server_type)
781                 {
782                         DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
783                                  cli->server_domain,
784                                  cli->server_os,
785                                  cli->server_type));
786                 }
787                 
788                 if (do_tcon)
789                 {
790                         if (!cli_send_tconX(cli, service, service_type,
791                                             (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
792                         {
793                                 DEBUG(1,("failed tcon_X\n"));
794                                 if (do_shutdown)
795                   cli_shutdown(cli);
796                                 return False;
797                         }
798                 }
799         }
800
801         if (do_shutdown)
802                 cli_shutdown(cli);
803
804         return True;
805 }
806
807
808 /****************************************************************************
809  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
810 ****************************************************************************/
811
812 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
813                                      struct in_addr *pdest_ip)
814 {
815   struct nmb_name calling, called;
816
817   make_nmb_name(&calling, srchost, 0x0);
818
819   /*
820    * If the called name is an IP address
821    * then use *SMBSERVER immediately.
822    */
823
824   if(is_ipaddress(desthost))
825     make_nmb_name(&called, "*SMBSERVER", 0x20);
826   else
827     make_nmb_name(&called, desthost, 0x20);
828
829   if (!cli_session_request(cli, &calling, &called)) {
830     struct nmb_name smbservername;
831
832     make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
833
834     /*
835      * If the name wasn't *SMBSERVER then
836      * try with *SMBSERVER if the first name fails.
837      */
838
839     if (nmb_name_equal(&called, &smbservername)) {
840
841         /*
842          * The name used was *SMBSERVER, don't bother with another name.
843          */
844
845         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
846 with error %s.\n", desthost, cli_errstr(cli) ));
847             cli_shutdown(cli);
848                 return False;
849         }
850
851     cli_shutdown(cli);
852
853     if (!cli_initialise(cli) ||
854         !cli_connect(cli, desthost, pdest_ip) ||
855         !cli_session_request(cli, &calling, &smbservername)) {
856           DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
857 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
858           cli_shutdown(cli);
859           return False;
860     }
861   }
862
863   return True;
864 }