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