fixed NTLMSSP with XP servers (who don't send the duplicate challenge
[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_LANMAN1,"LANMAN1.0"},
35       {PROTOCOL_LANMAN1,"Windows for Workgroups 3.1a"},
36       {PROTOCOL_LANMAN2,"LM1.2X002"},
37       {PROTOCOL_NT1,"Samba"},
38       {PROTOCOL_NT1,"LANMAN2.1"},
39       {PROTOCOL_NT1,"NT LM 0.12"},
40       {-1,NULL}
41     };
42
43
44 /****************************************************************************
45 do an old lanman2 style session setup
46 ****************************************************************************/
47 static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user, 
48                                       char *pass, int passlen)
49 {
50         fstring pword;
51         char *p;
52
53         if (passlen > sizeof(pword)-1) {
54                 return False;
55         }
56
57         /* if in share level security then don't send a password now */
58         if (!(cli->sec_mode & 1)) {
59                 passlen = 0;
60         }
61
62         if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
63                 /* Encrypted mode needed, and non encrypted password supplied. */
64                 passlen = 24;
65                 clistr_push(cli, pword, pass, -1, STR_TERMINATE);
66                 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
67         } else if ((cli->sec_mode & 2) && passlen == 24) {
68                 /* Encrypted mode needed, and encrypted password supplied. */
69                 memcpy(pword, pass, passlen);
70         } else if (passlen > 0) {
71                 /* Plaintext mode needed, assume plaintext supplied. */
72                 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
73         }
74
75         /* send a session setup command */
76         memset(cli->outbuf,'\0',smb_size);
77         set_message(cli->outbuf,10, 0, True);
78         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
79         cli_setup_packet(cli);
80         
81         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
82         SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
83         SSVAL(cli->outbuf,smb_vwv3,2);
84         SSVAL(cli->outbuf,smb_vwv4,1);
85         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
86         SSVAL(cli->outbuf,smb_vwv7,passlen);
87
88         p = smb_buf(cli->outbuf);
89         memcpy(p,pword,passlen);
90         p += passlen;
91         p += clistr_push(cli, p, user, -1, STR_UPPER|STR_TERMINATE);
92         cli_setup_bcc(cli, p);
93
94         cli_send_smb(cli);
95         if (!cli_receive_smb(cli))
96                 return False;
97
98         show_msg(cli->inbuf);
99
100         if (cli_is_error(cli)) {
101                 return False;
102         }
103         
104         /* use the returned vuid from now on */
105         cli->vuid = SVAL(cli->inbuf,smb_uid);   
106         fstrcpy(cli->user_name, user);
107
108         return True;
109 }
110
111
112 /****************************************************************************
113 work out suitable capabilities to offer the server
114 ****************************************************************************/
115 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
116 {
117         uint32 capabilities = CAP_NT_SMBS;
118
119         /* Set the CLI_FORCE_DOSERR environment variable to test
120            client routines using DOS errors instead of STATUS32
121            ones.  This intended only as a temporary hack. */    
122         if (!getenv("CLI_FORCE_DOSERR")) {
123                 capabilities |= CAP_STATUS32;
124         }
125
126         if (cli->use_level_II_oplocks) {
127                 capabilities |= CAP_LEVEL_II_OPLOCKS;
128         }
129
130         if (cli->capabilities & CAP_UNICODE) {
131                 capabilities |= CAP_UNICODE;
132         }
133
134         return capabilities;
135 }
136
137
138 /****************************************************************************
139 do a NT1 guest session setup
140 ****************************************************************************/
141 static BOOL cli_session_setup_guest(struct cli_state *cli)
142 {
143         char *p;
144         uint32 capabilities = cli_session_setup_capabilities(cli);
145
146         set_message(cli->outbuf,13,0,True);
147         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
148         cli_setup_packet(cli);
149                         
150         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
151         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
152         SSVAL(cli->outbuf,smb_vwv3,2);
153         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
154         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
155         SSVAL(cli->outbuf,smb_vwv7,0);
156         SSVAL(cli->outbuf,smb_vwv8,0);
157         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
158         p = smb_buf(cli->outbuf);
159         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
160         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
161         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
162         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
163         cli_setup_bcc(cli, p);
164
165         cli_send_smb(cli);
166         if (!cli_receive_smb(cli))
167               return False;
168         
169         show_msg(cli->inbuf);
170         
171         if (cli_is_error(cli)) {
172                 return False;
173         }
174
175         cli->vuid = SVAL(cli->inbuf,smb_uid);
176
177         p = smb_buf(cli->inbuf);
178         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
179         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
180         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
181
182         fstrcpy(cli->user_name, "");
183
184         return True;
185 }
186
187
188 /****************************************************************************
189 do a NT1 plaintext session setup
190 ****************************************************************************/
191 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user, 
192                                         char *pass, char *workgroup)
193 {
194         uint32 capabilities = cli_session_setup_capabilities(cli);
195         fstring pword;
196         int passlen;
197         char *p;
198
199         passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
200
201         set_message(cli->outbuf,13,0,True);
202         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
203         cli_setup_packet(cli);
204                         
205         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
206         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
207         SSVAL(cli->outbuf,smb_vwv3,2);
208         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
209         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
210         SSVAL(cli->outbuf,smb_vwv7,passlen);
211         SSVAL(cli->outbuf,smb_vwv8,0);
212         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
213         p = smb_buf(cli->outbuf);
214         memcpy(p, pword, passlen);
215         p += passlen;
216         p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
217         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
218         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
219         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
220         cli_setup_bcc(cli, p);
221
222         cli_send_smb(cli);
223         if (!cli_receive_smb(cli))
224               return False;
225         
226         show_msg(cli->inbuf);
227         
228         if (cli_is_error(cli)) {
229                 return False;
230         }
231
232         cli->vuid = SVAL(cli->inbuf,smb_uid);
233         p = smb_buf(cli->inbuf);
234         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
235         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
236         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
237         fstrcpy(cli->user_name, user);
238
239         return True;
240 }
241
242
243 /****************************************************************************
244 do a NT1 NTLM/LM encrypted session setup
245 ****************************************************************************/
246 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user, 
247                                   char *pass, int passlen,
248                                   char *ntpass, int ntpasslen,
249                                   char *workgroup)
250 {
251         uint32 capabilities = cli_session_setup_capabilities(cli);
252         fstring pword, ntpword;
253         char *p;
254
255         if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
256                 return False;
257         }
258
259         if (passlen != 24) {
260                 /* non encrypted password supplied. */
261                 passlen = 24;
262                 ntpasslen = 24;
263                 clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
264                 clistr_push(cli, ntpword, ntpass, sizeof(ntpword), STR_TERMINATE);
265                 SMBencrypt((uchar *)pword,cli->secblob.data,(uchar *)pword);
266                 SMBNTencrypt((uchar *)ntpword,cli->secblob.data,(uchar *)ntpword);
267         } else {
268                 memcpy(pword, pass, passlen);
269                 memcpy(ntpword, ntpass, ntpasslen);
270         }
271
272         /* send a session setup command */
273         memset(cli->outbuf,'\0',smb_size);
274
275         set_message(cli->outbuf,13,0,True);
276         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
277         cli_setup_packet(cli);
278                         
279         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
280         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
281         SSVAL(cli->outbuf,smb_vwv3,2);
282         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
283         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
284         SSVAL(cli->outbuf,smb_vwv7,passlen);
285         SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
286         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
287         p = smb_buf(cli->outbuf);
288         memcpy(p,pword,passlen); p += passlen;
289         memcpy(p,ntpword,ntpasslen); p += ntpasslen;
290         p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
291         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
292         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
293         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
294         cli_setup_bcc(cli, p);
295
296         cli_send_smb(cli);
297         if (!cli_receive_smb(cli))
298                 return False;
299
300         show_msg(cli->inbuf);
301
302         if (cli_is_error(cli)) {
303                 return False;
304         }
305         
306         /* use the returned vuid from now on */
307         cli->vuid = SVAL(cli->inbuf,smb_uid);
308         
309         p = smb_buf(cli->inbuf);
310         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
311         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
312         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
313
314         fstrcpy(cli->user_name, user);
315
316         return True;
317 }
318
319
320 /****************************************************************************
321 send a extended security session setup blob, returning a reply blob
322 ****************************************************************************/
323 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
324 {
325         uint32 capabilities = cli_session_setup_capabilities(cli);
326         char *p;
327         DATA_BLOB blob2;
328
329         blob2 = data_blob(NULL, 0);
330
331         capabilities |= CAP_EXTENDED_SECURITY;
332
333         /* send a session setup command */
334         memset(cli->outbuf,'\0',smb_size);
335
336         set_message(cli->outbuf,12,0,True);
337         CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
338         cli_setup_packet(cli);
339                         
340         CVAL(cli->outbuf,smb_vwv0) = 0xFF;
341         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
342         SSVAL(cli->outbuf,smb_vwv3,2);
343         SSVAL(cli->outbuf,smb_vwv4,0);
344         SIVAL(cli->outbuf,smb_vwv5,0);
345         SSVAL(cli->outbuf,smb_vwv7,blob.length);
346         SIVAL(cli->outbuf,smb_vwv10,capabilities); 
347         p = smb_buf(cli->outbuf);
348         memcpy(p, blob.data, blob.length);
349         p += blob.length;
350         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
351         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
352         cli_setup_bcc(cli, p);
353
354         cli_send_smb(cli);
355         if (!cli_receive_smb(cli))
356                 return blob2;
357
358         show_msg(cli->inbuf);
359
360         if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
361                                                   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
362                 return blob2;
363         }
364         
365         /* use the returned vuid from now on */
366         cli->vuid = SVAL(cli->inbuf,smb_uid);
367         
368         p = smb_buf(cli->inbuf);
369
370         blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
371
372         p += blob2.length;
373         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
374         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
375         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
376
377         return blob2;
378 }
379
380
381 #if HAVE_KRB5
382 /****************************************************************************
383 do a spnego/kerberos encrypted session setup
384 ****************************************************************************/
385 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principle, char *workgroup)
386 {
387         DATA_BLOB blob2, negTokenTarg;
388
389         /* generate the encapsulated kerberos5 ticket */
390         negTokenTarg = spnego_gen_negTokenTarg(cli, principle);
391
392         if (!negTokenTarg.data) return False;
393
394         blob2 = cli_session_setup_blob(cli, negTokenTarg);
395
396         /* we don't need this blob for kerberos */
397         data_blob_free(blob2);
398
399         return !cli_is_error(cli);
400 }
401 #endif
402
403 /****************************************************************************
404 do a spnego/NTLMSSP encrypted session setup
405 ****************************************************************************/
406 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user, 
407                                       char *pass, char *workgroup)
408 {
409         const char *mechs[] = {OID_NTLMSSP, NULL};
410         DATA_BLOB msg1;
411         DATA_BLOB blob, chal1, chal2, auth;
412         uint8 challenge[8];
413         uint8 nthash[24], lmhash[24], sess_key[16];
414         uint32 neg_flags;
415
416         neg_flags = NTLMSSP_NEGOTIATE_UNICODE | 
417                 NTLMSSP_NEGOTIATE_LM_KEY | 
418                 NTLMSSP_NEGOTIATE_NTLM;
419
420         memset(sess_key, 0, 16);
421
422         /* generate the ntlmssp negotiate packet */
423         msrpc_gen(&blob, "CddB",
424                   "NTLMSSP",
425                   NTLMSSP_NEGOTIATE,
426                   neg_flags,
427                   sess_key, 16);
428
429         /* and wrap it in a SPNEGO wrapper */
430         msg1 = gen_negTokenTarg(mechs, blob);
431         data_blob_free(blob);           
432
433         /* now send that blob on its way */
434         blob = cli_session_setup_blob(cli, msg1);
435
436         data_blob_free(msg1); 
437
438         if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
439                 return False;
440         }
441
442 #if 0
443         file_save("chal.dat", blob.data, blob.length);
444 #endif
445
446         /* the server gives us back two challenges */
447         if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
448                 return False;
449         }
450
451         data_blob_free(blob);           
452
453         /* encrypt the password with the challenge */
454         memcpy(challenge, chal1.data + 24, 8);
455         SMBencrypt(pass, challenge,lmhash);
456         SMBNTencrypt(pass, challenge,nthash);
457
458         data_blob_free(chal1);
459         data_blob_free(chal2);
460
461         /* this generates the actual auth packet */
462         msrpc_gen(&blob, "CdBBUUUBd", 
463                   "NTLMSSP", 
464                   NTLMSSP_AUTH, 
465                   lmhash, 24,
466                   nthash, 24,
467                   workgroup, 
468                   user, 
469                   cli->calling.name,
470                   sess_key, 16,
471                   neg_flags);
472
473         /* wrap it in SPNEGO */
474         auth = spnego_gen_auth(blob);
475
476         data_blob_free(blob);
477
478         /* now send the auth packet and we should be done */
479         blob = cli_session_setup_blob(cli, auth);
480
481         data_blob_free(auth);
482         data_blob_free(blob);
483
484         return !cli_is_error(cli);
485 }
486
487
488 /****************************************************************************
489 do a spnego encrypted session setup
490 ****************************************************************************/
491 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user, 
492                                      char *pass, char *workgroup)
493 {
494         char *principle;
495         char *OIDs[ASN1_MAX_OIDS];
496         uint8 guid[16];
497         int i;
498         BOOL got_kerberos_mechanism = False;
499
500         /* the server might not even do spnego */
501         if (cli->secblob.length == 16) {
502                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
503                 goto ntlmssp;
504         }
505
506 #if 0
507         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
508 #endif
509
510         /* the server sent us the first part of the SPNEGO exchange in the negprot 
511            reply */
512         if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principle)) {
513                 return False;
514         }
515
516         /* make sure the server understands kerberos */
517         for (i=0;OIDs[i];i++) {
518                 DEBUG(3,("got OID=%s\n", OIDs[i]));
519                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0) {
520                         got_kerberos_mechanism = True;
521                 }
522                 free(OIDs[i]);
523         }
524         DEBUG(3,("got principle=%s\n", principle));
525
526         fstrcpy(cli->user_name, user);
527
528 #if HAVE_KRB5
529         if (got_kerberos_mechanism && cli->use_kerberos) {
530                 return cli_session_setup_kerberos(cli, principle, workgroup);
531         }
532 #endif
533
534         free(principle);
535
536 ntlmssp:
537
538         return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
539 }
540
541
542 /****************************************************************************
543  Send a session setup. The username and workgroup is in UNIX character
544  format and must be converted to DOS codepage format before sending. If the
545  password is in plaintext, the same should be done.
546 ****************************************************************************/
547 BOOL cli_session_setup(struct cli_state *cli, 
548                        char *user, 
549                        char *pass, int passlen,
550                        char *ntpass, int ntpasslen,
551                        char *workgroup)
552 {
553         char *p;
554         fstring user2;
555
556         /* allow for workgroups as part of the username */
557         fstrcpy(user2, user);
558         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/'))) {
559                 *p = 0;
560                 user = p+1;
561                 workgroup = user2;
562         }
563
564         if (cli->protocol < PROTOCOL_LANMAN1)
565                 return True;
566
567         /* now work out what sort of session setup we are going to
568            do. I have split this into separate functions to make the
569            flow a bit easier to understand (tridge) */
570
571         /* if its an older server then we have to use the older request format */
572         if (cli->protocol < PROTOCOL_NT1) {
573                 return cli_session_setup_lanman2(cli, user, pass, passlen);
574         }
575
576         /* if no user is supplied then we have to do an anonymous connection.
577            passwords are ignored */
578         if (!user || !*user) {
579                 return cli_session_setup_guest(cli);
580         }
581
582         /* if the server is share level then send a plaintext null
583            password at this point. The password is sent in the tree
584            connect */
585         if ((cli->sec_mode & 1) == 0) {
586                 return cli_session_setup_plaintext(cli, user, "", workgroup);
587         }
588
589         /* if the server doesn't support encryption then we have to use plaintext. The 
590            second password is ignored */
591         if ((cli->sec_mode & 2) == 0) {
592                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
593         }
594
595         /* if the server supports extended security then use SPNEGO */
596         if (cli->capabilities & CAP_EXTENDED_SECURITY) {
597                 return cli_session_setup_spnego(cli, user, pass, workgroup);
598         }
599
600         /* otherwise do a NT1 style session setup */
601         return cli_session_setup_nt1(cli, user, 
602                                      pass, passlen, ntpass, ntpasslen,
603                                      workgroup);        
604 }
605
606 /****************************************************************************
607  Send a uloggoff.
608 *****************************************************************************/
609
610 BOOL cli_ulogoff(struct cli_state *cli)
611 {
612         memset(cli->outbuf,'\0',smb_size);
613         set_message(cli->outbuf,2,0,True);
614         CVAL(cli->outbuf,smb_com) = SMBulogoffX;
615         cli_setup_packet(cli);
616         SSVAL(cli->outbuf,smb_vwv0,0xFF);
617         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
618
619         cli_send_smb(cli);
620         if (!cli_receive_smb(cli))
621                 return False;
622
623         return !cli_is_error(cli);
624 }
625
626 /****************************************************************************
627 send a tconX
628 ****************************************************************************/
629 BOOL cli_send_tconX(struct cli_state *cli, 
630                     const char *share, const char *dev, const char *pass, int passlen)
631 {
632         fstring fullshare, pword, dos_pword;
633         char *p;
634         memset(cli->outbuf,'\0',smb_size);
635         memset(cli->inbuf,'\0',smb_size);
636
637         fstrcpy(cli->share, share);
638
639         /* in user level security don't send a password now */
640         if (cli->sec_mode & 1) {
641                 passlen = 1;
642                 pass = "";
643         }
644
645         if ((cli->sec_mode & 2) && *pass && passlen != 24) {
646                 /*
647                  * Non-encrypted passwords - convert to DOS codepage before encryption.
648                  */
649                 passlen = 24;
650                 clistr_push(cli, dos_pword, pass, -1, STR_TERMINATE);
651                 SMBencrypt((uchar *)dos_pword,cli->secblob.data,(uchar *)pword);
652         } else {
653                 if((cli->sec_mode & 3) == 0) {
654                         /*
655                          * Non-encrypted passwords - convert to DOS codepage before using.
656                          */
657                         passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
658                 } else {
659                         memcpy(pword, pass, passlen);
660                 }
661         }
662
663         if (cli->port == 445) {
664                 slprintf(fullshare, sizeof(fullshare)-1,
665                          "%s", share);
666         } else {
667                 slprintf(fullshare, sizeof(fullshare)-1,
668                          "\\\\%s\\%s", cli->desthost, share);
669         }
670
671         set_message(cli->outbuf,4, 0, True);
672         CVAL(cli->outbuf,smb_com) = SMBtconX;
673         cli_setup_packet(cli);
674
675         SSVAL(cli->outbuf,smb_vwv0,0xFF);
676         SSVAL(cli->outbuf,smb_vwv3,passlen);
677
678         p = smb_buf(cli->outbuf);
679         memcpy(p,pword,passlen);
680         p += passlen;
681         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
682         fstrcpy(p, dev); p += strlen(dev)+1;
683
684         cli_setup_bcc(cli, p);
685
686         cli_send_smb(cli);
687         if (!cli_receive_smb(cli))
688                 return False;
689
690         if (cli_is_error(cli)) {
691                 return False;
692         }
693
694         fstrcpy(cli->dev, "A:");
695
696         if (cli->protocol >= PROTOCOL_NT1) {
697                 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE);
698         }
699
700         if (strcasecmp(share,"IPC$")==0) {
701                 fstrcpy(cli->dev, "IPC");
702         }
703
704         /* only grab the device if we have a recent protocol level */
705         if (cli->protocol >= PROTOCOL_NT1 &&
706             smb_buflen(cli->inbuf) == 3) {
707                 /* almost certainly win95 - enable bug fixes */
708                 cli->win95 = True;
709         }
710
711         cli->cnum = SVAL(cli->inbuf,smb_tid);
712         return True;
713 }
714
715
716 /****************************************************************************
717 send a tree disconnect
718 ****************************************************************************/
719 BOOL cli_tdis(struct cli_state *cli)
720 {
721         memset(cli->outbuf,'\0',smb_size);
722         set_message(cli->outbuf,0,0,True);
723         CVAL(cli->outbuf,smb_com) = SMBtdis;
724         SSVAL(cli->outbuf,smb_tid,cli->cnum);
725         cli_setup_packet(cli);
726         
727         cli_send_smb(cli);
728         if (!cli_receive_smb(cli))
729                 return False;
730         
731         return !cli_is_error(cli);
732 }
733
734
735 /****************************************************************************
736 send a negprot command
737 ****************************************************************************/
738 void cli_negprot_send(struct cli_state *cli)
739 {
740         char *p;
741         int numprots;
742
743         memset(cli->outbuf,'\0',smb_size);
744
745         /* setup the protocol strings */
746         set_message(cli->outbuf,0,0,True);
747
748         p = smb_buf(cli->outbuf);
749         for (numprots=0;
750              prots[numprots].name && prots[numprots].prot<=cli->protocol;
751              numprots++) {
752                 *p++ = 2;
753                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
754         }
755
756         CVAL(cli->outbuf,smb_com) = SMBnegprot;
757         cli_setup_bcc(cli, p);
758         cli_setup_packet(cli);
759
760         CVAL(smb_buf(cli->outbuf),0) = 2;
761
762         cli_send_smb(cli);
763 }
764
765
766 /****************************************************************************
767 send a negprot command
768 ****************************************************************************/
769 BOOL cli_negprot(struct cli_state *cli)
770 {
771         char *p;
772         int numprots;
773         int plength;
774
775         memset(cli->outbuf,'\0',smb_size);
776
777         /* setup the protocol strings */
778         for (plength=0,numprots=0;
779              prots[numprots].name && prots[numprots].prot<=cli->protocol;
780              numprots++)
781                 plength += strlen(prots[numprots].name)+2;
782     
783         set_message(cli->outbuf,0,plength,True);
784
785         p = smb_buf(cli->outbuf);
786         for (numprots=0;
787              prots[numprots].name && prots[numprots].prot<=cli->protocol;
788              numprots++) {
789                 *p++ = 2;
790                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
791         }
792
793         CVAL(cli->outbuf,smb_com) = SMBnegprot;
794         cli_setup_packet(cli);
795
796         CVAL(smb_buf(cli->outbuf),0) = 2;
797
798         cli_send_smb(cli);
799         if (!cli_receive_smb(cli))
800                 return False;
801
802         show_msg(cli->inbuf);
803
804         if (cli_is_error(cli) ||
805             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
806                 return(False);
807         }
808
809         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
810
811         if (cli->protocol >= PROTOCOL_NT1) {    
812                 /* NT protocol */
813                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
814                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
815                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
816                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
817                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
818                 cli->serverzone *= 60;
819                 /* this time arrives in real GMT */
820                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
821                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
822                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
823                 if (cli->capabilities & CAP_RAW_MODE) {
824                         cli->readbraw_supported = True;
825                         cli->writebraw_supported = True;      
826                 }
827                 /* work out if they sent us a workgroup */
828                 if (smb_buflen(cli->inbuf) > 8) {
829                         clistr_pull(cli, cli->server_domain, 
830                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
831                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
832                 }
833         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
834                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
835                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
836                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
837                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
838                 cli->serverzone *= 60;
839                 /* this time is converted to GMT by make_unix_date */
840                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
841                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
842                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
843                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
844         } else {
845                 /* the old core protocol */
846                 cli->sec_mode = 0;
847                 cli->serverzone = TimeDiff(time(NULL));
848         }
849
850         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
851
852         /* a way to force ascii SMB */
853         if (getenv("CLI_FORCE_ASCII")) {
854                 cli->capabilities &= ~CAP_UNICODE;
855         }
856
857         return True;
858 }
859
860
861 /****************************************************************************
862   send a session request.  see rfc1002.txt 4.3 and 4.3.2
863 ****************************************************************************/
864 BOOL cli_session_request(struct cli_state *cli,
865                          struct nmb_name *calling, struct nmb_name *called)
866 {
867         char *p;
868         int len = 4;
869         extern pstring user_socket_options;
870
871         /* 445 doesn't have session request */
872         if (cli->port == 445) return True;
873
874         /* send a session request (RFC 1002) */
875         memcpy(&(cli->calling), calling, sizeof(*calling));
876         memcpy(&(cli->called ), called , sizeof(*called ));
877   
878         /* put in the destination name */
879         p = cli->outbuf+len;
880         name_mangle(cli->called .name, p, cli->called .name_type);
881         len += name_len(p);
882
883         /* and my name */
884         p = cli->outbuf+len;
885         name_mangle(cli->calling.name, p, cli->calling.name_type);
886         len += name_len(p);
887
888         /* setup the packet length */
889         _smb_setlen(cli->outbuf,len);
890         CVAL(cli->outbuf,0) = 0x81;
891
892 #ifdef WITH_SSL
893 retry:
894 #endif /* WITH_SSL */
895
896         cli_send_smb(cli);
897         DEBUG(5,("Sent session request\n"));
898
899         if (!cli_receive_smb(cli))
900                 return False;
901
902         if (CVAL(cli->inbuf,0) == 0x84) {
903                 /* C. Hoch  9/14/95 Start */
904                 /* For information, here is the response structure.
905                  * We do the byte-twiddling to for portability.
906                 struct RetargetResponse{
907                 unsigned char type;
908                 unsigned char flags;
909                 int16 length;
910                 int32 ip_addr;
911                 int16 port;
912                 };
913                 */
914                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
915                 /* SESSION RETARGET */
916                 putip((char *)&cli->dest_ip,cli->inbuf+4);
917
918                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
919                 if (cli->fd == -1)
920                         return False;
921
922                 DEBUG(3,("Retargeted\n"));
923
924                 set_socket_options(cli->fd,user_socket_options);
925
926                 /* Try again */
927                 {
928                         static int depth;
929                         BOOL ret;
930                         if (depth > 4) {
931                                 DEBUG(0,("Retarget recursion - failing\n"));
932                                 return False;
933                         }
934                         depth++;
935                         ret = cli_session_request(cli, calling, called);
936                         depth--;
937                         return ret;
938                 }
939         } /* C. Hoch 9/14/95 End */
940
941 #ifdef WITH_SSL
942     if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
943         if (!sslutil_fd_is_ssl(cli->fd)){
944             if (sslutil_connect(cli->fd) == 0)
945                 goto retry;
946         }
947     }
948 #endif /* WITH_SSL */
949
950         if (CVAL(cli->inbuf,0) != 0x82) {
951                 /* This is the wrong place to put the error... JRA. */
952                 cli->rap_error = CVAL(cli->inbuf,4);
953                 return False;
954         }
955         return(True);
956 }
957
958 /****************************************************************************
959 open the client sockets
960 ****************************************************************************/
961 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
962 {
963         extern struct in_addr ipzero;
964         extern pstring user_socket_options;
965
966         fstrcpy(cli->desthost, host);
967         
968         if (!ip || ip_equal(*ip, ipzero)) {
969                 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
970                         return False;
971                 }
972                 if (ip) *ip = cli->dest_ip;
973         } else {
974                 cli->dest_ip = *ip;
975         }
976
977         if (getenv("LIBSMB_PROG")) {
978                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
979         } else {
980                 /* try 445 first, then 139 */
981                 int port = cli->port?cli->port:445;
982                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
983                                           port, cli->timeout);
984                 if (cli->fd == -1 && cli->port == 0) {
985                         port = 139;
986                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
987                                                   port, cli->timeout);
988                 }
989                 if (cli->fd != -1) cli->port = port;
990         }
991         if (cli->fd == -1) {
992                 DEBUG(1,("Error connecting to %s (%s)\n",
993                          inet_ntoa(*ip),strerror(errno)));
994                 return False;
995         }
996
997         set_socket_options(cli->fd,user_socket_options);
998
999         return True;
1000 }
1001
1002 /****************************************************************************
1003 re-establishes a connection
1004 ****************************************************************************/
1005 BOOL cli_reestablish_connection(struct cli_state *cli)
1006 {
1007         struct nmb_name calling;
1008         struct nmb_name called;
1009         fstring dest_host;
1010         fstring share;
1011         fstring dev;
1012         BOOL do_tcon = False;
1013         int oldfd = cli->fd;
1014
1015         if (!cli->initialised || cli->fd == -1)
1016         {
1017                 DEBUG(3,("cli_reestablish_connection: not connected\n"));
1018                 return False;
1019         }
1020
1021         /* copy the parameters necessary to re-establish the connection */
1022
1023         if (cli->cnum != 0)
1024         {
1025                 fstrcpy(share, cli->share);
1026                 fstrcpy(dev  , cli->dev);
1027                 do_tcon = True;
1028         }
1029
1030         memcpy(&called , &(cli->called ), sizeof(called ));
1031         memcpy(&calling, &(cli->calling), sizeof(calling));
1032         fstrcpy(dest_host, cli->full_dest_host_name);
1033
1034         DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
1035                  nmb_namestr(&calling), nmb_namestr(&called), 
1036                  inet_ntoa(cli->dest_ip),
1037                  cli->user_name, cli->domain));
1038
1039         cli->fd = -1;
1040
1041         if (cli_establish_connection(cli,
1042                                      dest_host, &cli->dest_ip,
1043                                      &calling, &called,
1044                                      share, dev, False, do_tcon)) {
1045                 if ((cli->fd != oldfd) && (oldfd != -1)) {
1046                         close( oldfd );
1047                 }
1048                 return True;
1049         }
1050         return False;
1051 }
1052
1053 /****************************************************************************
1054 establishes a connection right up to doing tconX, reading in a password.
1055 ****************************************************************************/
1056 BOOL cli_establish_connection(struct cli_state *cli, 
1057                                 char *dest_host, struct in_addr *dest_ip,
1058                                 struct nmb_name *calling, struct nmb_name *called,
1059                                 char *service, char *service_type,
1060                                 BOOL do_shutdown, BOOL do_tcon)
1061 {
1062         DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
1063                           nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
1064                       cli->user_name, cli->domain));
1065
1066         /* establish connection */
1067
1068         if ((!cli->initialised))
1069         {
1070                 return False;
1071         }
1072
1073         if (cli->fd == -1)
1074         {
1075                 if (!cli_connect(cli, dest_host, dest_ip))
1076                 {
1077                         DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
1078                                           nmb_namestr(called), inet_ntoa(*dest_ip)));
1079                         return False;
1080                 }
1081         }
1082
1083         if (!cli_session_request(cli, calling, called))
1084         {
1085                 DEBUG(1,("failed session request\n"));
1086                 if (do_shutdown)
1087                         cli_shutdown(cli);
1088                 return False;
1089         }
1090
1091         if (!cli_negprot(cli))
1092         {
1093                 DEBUG(1,("failed negprot\n"));
1094                 if (do_shutdown)
1095                         cli_shutdown(cli);
1096                 return False;
1097         }
1098
1099         if (cli->pwd.cleartext || cli->pwd.null_pwd)
1100         {
1101                 fstring passwd;
1102                 int pass_len;
1103
1104                 if (cli->pwd.null_pwd)
1105                 {
1106                         /* attempt null session */
1107                         passwd[0] = 0;
1108                         pass_len = 1;
1109                 }
1110                 else
1111                 {
1112                         /* attempt clear-text session */
1113                         pwd_get_cleartext(&(cli->pwd), passwd);
1114                         pass_len = strlen(passwd);
1115                 }
1116
1117                 /* attempt clear-text session */
1118                 if (!cli_session_setup(cli, cli->user_name,
1119                                passwd, pass_len,
1120                                NULL, 0,
1121                                cli->domain))
1122                 {
1123                         DEBUG(1,("failed session setup\n"));
1124                         if (do_shutdown)
1125                         {
1126                                 cli_shutdown(cli);
1127                         }
1128                         return False;
1129                 }
1130                 if (do_tcon)
1131                 {
1132                         if (!cli_send_tconX(cli, service, service_type,
1133                                             (char*)passwd, strlen(passwd)))
1134                         {
1135                                 DEBUG(1,("failed tcon_X\n"));
1136                                 if (do_shutdown)
1137                                 {
1138                                         cli_shutdown(cli);
1139                                 }
1140                                 return False;
1141                         }
1142                 }
1143         }
1144         else
1145         {
1146                 /* attempt encrypted session */
1147                 unsigned char nt_sess_pwd[24];
1148                 unsigned char lm_sess_pwd[24];
1149
1150                 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
1151                 pwd_make_lm_nt_owf(&(cli->pwd), cli->secblob.data);
1152                 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
1153
1154                 /* attempt encrypted session */
1155                 if (!cli_session_setup(cli, cli->user_name,
1156                                (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
1157                                (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
1158                                cli->domain))
1159                 {
1160                         DEBUG(1,("failed session setup\n"));
1161                         if (do_shutdown)
1162                               cli_shutdown(cli);
1163                         return False;
1164                 }
1165
1166                 DEBUG(1,("session setup ok\n"));
1167     
1168                 if (*cli->server_domain || *cli->server_os || *cli->server_type)
1169                 {
1170                         DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
1171                                  cli->server_domain,
1172                                  cli->server_os,
1173                                  cli->server_type));
1174                 }
1175                 
1176                 if (do_tcon)
1177                 {
1178                         if (!cli_send_tconX(cli, service, service_type,
1179                                             (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
1180                         {
1181                                 DEBUG(1,("failed tcon_X\n"));
1182                                 if (do_shutdown)
1183                   cli_shutdown(cli);
1184                                 return False;
1185                         }
1186                 }
1187         }
1188
1189         if (do_shutdown)
1190                 cli_shutdown(cli);
1191
1192         return True;
1193 }
1194
1195
1196 /****************************************************************************
1197  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1198 ****************************************************************************/
1199
1200 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1201                                      struct in_addr *pdest_ip)
1202 {
1203   struct nmb_name calling, called;
1204
1205   make_nmb_name(&calling, srchost, 0x0);
1206
1207   /*
1208    * If the called name is an IP address
1209    * then use *SMBSERVER immediately.
1210    */
1211
1212   if(is_ipaddress(desthost))
1213     make_nmb_name(&called, "*SMBSERVER", 0x20);
1214   else
1215     make_nmb_name(&called, desthost, 0x20);
1216
1217   if (!cli_session_request(cli, &calling, &called)) {
1218     struct nmb_name smbservername;
1219
1220     make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1221
1222     /*
1223      * If the name wasn't *SMBSERVER then
1224      * try with *SMBSERVER if the first name fails.
1225      */
1226
1227     if (nmb_name_equal(&called, &smbservername)) {
1228
1229         /*
1230          * The name used was *SMBSERVER, don't bother with another name.
1231          */
1232
1233         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1234 with error %s.\n", desthost, cli_errstr(cli) ));
1235             cli_shutdown(cli);
1236                 return False;
1237         }
1238
1239     cli_shutdown(cli);
1240
1241     if (!cli_initialise(cli) ||
1242         !cli_connect(cli, desthost, pdest_ip) ||
1243         !cli_session_request(cli, &calling, &smbservername)) {
1244           DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1245 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1246           cli_shutdown(cli);
1247           return False;
1248     }
1249   }
1250
1251   return True;
1252 }