updated the 3.0 branch from the head branch - ready for alpha18
[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          * Remove four bytes from the length count, since the length
957          * field in the NBT Session Service header counts the number
958          * of bytes which follow.  The cli_send_smb() function knows
959          * about this and accounts for those four bytes.
960          * CRH.
961          */
962         len -= 4;
963         _smb_setlen(cli->outbuf,len);
964         SCVAL(cli->outbuf,0,0x81);
965
966         cli_send_smb(cli);
967         DEBUG(5,("Sent session request\n"));
968
969         if (!cli_receive_smb(cli))
970                 return False;
971
972         if (CVAL(cli->inbuf,0) == 0x84) {
973                 /* C. Hoch  9/14/95 Start */
974                 /* For information, here is the response structure.
975                  * We do the byte-twiddling to for portability.
976                 struct RetargetResponse{
977                 unsigned char type;
978                 unsigned char flags;
979                 int16 length;
980                 int32 ip_addr;
981                 int16 port;
982                 };
983                 */
984                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
985                 /* SESSION RETARGET */
986                 putip((char *)&cli->dest_ip,cli->inbuf+4);
987
988                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
989                 if (cli->fd == -1)
990                         return False;
991
992                 DEBUG(3,("Retargeted\n"));
993
994                 set_socket_options(cli->fd,user_socket_options);
995
996                 /* Try again */
997                 {
998                         static int depth;
999                         BOOL ret;
1000                         if (depth > 4) {
1001                                 DEBUG(0,("Retarget recursion - failing\n"));
1002                                 return False;
1003                         }
1004                         depth++;
1005                         ret = cli_session_request(cli, calling, called);
1006                         depth--;
1007                         return ret;
1008                 }
1009         } /* C. Hoch 9/14/95 End */
1010
1011         if (CVAL(cli->inbuf,0) != 0x82) {
1012                 /* This is the wrong place to put the error... JRA. */
1013                 cli->rap_error = CVAL(cli->inbuf,4);
1014                 return False;
1015         }
1016         return(True);
1017 }
1018
1019 /****************************************************************************
1020  Open the client sockets.
1021 ****************************************************************************/
1022
1023 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1024 {
1025         extern pstring user_socket_options;
1026         int name_type = 0x20;
1027         char *p;
1028
1029         /* reasonable default hostname */
1030         if (!host) host = "*SMBSERVER";
1031
1032         fstrcpy(cli->desthost, host);
1033
1034         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1035         if ((p = strchr(cli->desthost, '#'))) {
1036                 name_type = strtol(p+1, NULL, 16);              
1037                 *p = 0;
1038         }
1039         
1040         if (!ip || is_zero_ip(*ip)) {
1041                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1042                         return False;
1043                 }
1044                 if (ip) *ip = cli->dest_ip;
1045         } else {
1046                 cli->dest_ip = *ip;
1047         }
1048
1049         if (getenv("LIBSMB_PROG")) {
1050                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1051         } else {
1052                 /* try 445 first, then 139 */
1053                 int port = cli->port?cli->port:445;
1054                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1055                                           port, cli->timeout);
1056                 if (cli->fd == -1 && cli->port == 0) {
1057                         port = 139;
1058                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1059                                                   port, cli->timeout);
1060                 }
1061                 if (cli->fd != -1) cli->port = port;
1062         }
1063         if (cli->fd == -1) {
1064                 DEBUG(1,("Error connecting to %s (%s)\n",
1065                          inet_ntoa(*ip),strerror(errno)));
1066                 return False;
1067         }
1068
1069         set_socket_options(cli->fd,user_socket_options);
1070
1071         return True;
1072 }
1073
1074 /****************************************************************************
1075  Initialise client credentials for authenticated pipe access.
1076 ****************************************************************************/
1077
1078 static void init_creds(struct ntuser_creds *creds, char* username,
1079                        char* domain, char* password)
1080 {
1081         ZERO_STRUCTP(creds);
1082
1083         pwd_set_cleartext(&creds->pwd, password);
1084
1085         fstrcpy(creds->user_name, username);
1086         fstrcpy(creds->domain, domain);
1087
1088         if (!*username) {
1089                 creds->pwd.null_pwd = True;
1090         }
1091 }
1092
1093 /**
1094    establishes a connection right up to doing tconX, password specified.
1095    @param output_cli A fully initialised cli structure, non-null only on success
1096    @param dest_host The netbios name of the remote host
1097    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1098    @param port (optional) The destination port (0 for default)
1099    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1100    @param service_type The 'type' of serivice. 
1101    @param user Username, unix string
1102    @param domain User's domain
1103    @param password User's password, unencrypted unix string.
1104 */
1105
1106 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1107                              const char *my_name, 
1108                              const char *dest_host, 
1109                              struct in_addr *dest_ip, int port,
1110                              char *service, char *service_type,
1111                              char *user, char *domain, 
1112                              char *password, int flags) 
1113 {
1114         struct ntuser_creds creds;
1115         NTSTATUS nt_status;
1116         struct nmb_name calling;
1117         struct nmb_name called;
1118         struct cli_state *cli;
1119         struct in_addr ip;
1120         extern pstring global_myname;
1121
1122         if (!output_cli) {
1123                 DEBUG(0, ("output_cli is NULL!?!"));
1124                 SMB_ASSERT("output_cli for cli_full_connection was NULL.\n");
1125         }
1126
1127         if (!my_name) 
1128                 my_name = global_myname;
1129         
1130         if (!(cli = cli_initialise(NULL)))
1131                 return NT_STATUS_NO_MEMORY;
1132         
1133         make_nmb_name(&calling, my_name, 0x0);
1134         make_nmb_name(&called , dest_host, 0x20);
1135
1136         if (cli_set_port(cli, port) != port) {
1137                 cli_shutdown(cli);
1138                 return NT_STATUS_UNSUCCESSFUL;
1139         }
1140
1141         if (dest_ip) {
1142                 ip = *dest_ip;
1143         } else {
1144                 ZERO_STRUCT(ip);
1145         }
1146
1147 again:
1148
1149         DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1150         
1151         if (!cli_connect(cli, dest_host, &ip)) {
1152                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1153                          nmb_namestr(&called), inet_ntoa(ip)));
1154                 cli_shutdown(cli);
1155                 return NT_STATUS_UNSUCCESSFUL;
1156         }
1157
1158         if (!cli_session_request(cli, &calling, &called)) {
1159                 char *p;
1160                 DEBUG(1,("session request to %s failed (%s)\n", 
1161                          called.name, cli_errstr(cli)));
1162                 cli_shutdown(cli);
1163                 if ((p=strchr(called.name, '.'))) {
1164                         *p = 0;
1165                         goto again;
1166                 }
1167                 if (strcmp(called.name, "*SMBSERVER")) {
1168                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1169                         goto again;
1170                 }
1171                 return NT_STATUS_UNSUCCESSFUL;
1172         }
1173
1174         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
1175                 cli->use_spnego = False;
1176         } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
1177                 cli->use_kerberos = True;
1178         }
1179
1180         if (!cli_negprot(cli)) {
1181                 DEBUG(1,("failed negprot\n"));
1182                 nt_status = NT_STATUS_UNSUCCESSFUL;
1183                 cli_shutdown(cli);
1184                 return nt_status;
1185         }
1186
1187         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1188                                password, strlen(password)+1, 
1189                                domain)) {
1190                 if (!(flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK) 
1191                     || cli_session_setup(cli, "", "", 0, 
1192                                          "", 0, domain)) {
1193                 } else {
1194                         nt_status = cli_nt_error(cli);
1195                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1196                         cli_shutdown(cli);
1197                         if (NT_STATUS_IS_OK(nt_status)) 
1198                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1199                         return nt_status;
1200                 }
1201         } 
1202
1203         if (service) {
1204                 if (!cli_send_tconX(cli, service, service_type,
1205                                     (char*)password, strlen(password)+1)) {
1206                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1207                         nt_status = cli_nt_error(cli);
1208                         cli_shutdown(cli);
1209                         if (NT_STATUS_IS_OK(nt_status)) {
1210                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1211                         }
1212                         return nt_status;
1213                 }
1214         }
1215
1216         init_creds(&creds, user, domain, password);
1217         cli_init_creds(cli, &creds);
1218
1219         *output_cli = cli;
1220         return NT_STATUS_OK;
1221 }
1222
1223 /****************************************************************************
1224  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1225 ****************************************************************************/
1226
1227 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1228                                      struct in_addr *pdest_ip)
1229 {
1230         struct nmb_name calling, called;
1231
1232         make_nmb_name(&calling, srchost, 0x0);
1233
1234         /*
1235          * If the called name is an IP address
1236          * then use *SMBSERVER immediately.
1237          */
1238
1239         if(is_ipaddress(desthost))
1240                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1241         else
1242                 make_nmb_name(&called, desthost, 0x20);
1243
1244         if (!cli_session_request(cli, &calling, &called)) {
1245                 struct nmb_name smbservername;
1246
1247                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1248
1249                 /*
1250                  * If the name wasn't *SMBSERVER then
1251                  * try with *SMBSERVER if the first name fails.
1252                  */
1253
1254                 if (nmb_name_equal(&called, &smbservername)) {
1255
1256                         /*
1257                          * The name used was *SMBSERVER, don't bother with another name.
1258                          */
1259
1260                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1261 with error %s.\n", desthost, cli_errstr(cli) ));
1262                         cli_shutdown(cli);
1263                         return False;
1264                 }
1265
1266                 cli_shutdown(cli);
1267
1268                 if (!cli_initialise(cli) ||
1269                                 !cli_connect(cli, desthost, pdest_ip) ||
1270                                 !cli_session_request(cli, &calling, &smbservername)) {
1271                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1272 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1273                         cli_shutdown(cli);
1274                         return False;
1275                 }
1276         }
1277
1278         return True;
1279 }