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