Update cli_full_connection() to take a 'flags' paramater, and try to get a
[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 0 /* JRATEST for signing. */
639         /* if the server supports extended security then use SPNEGO */
640         if (cli->capabilities & CAP_EXTENDED_SECURITY) {
641                 return cli_session_setup_spnego(cli, user, pass, workgroup);
642         }
643 #endif
644
645         /* otherwise do a NT1 style session setup */
646         return cli_session_setup_nt1(cli, user, 
647                                      pass, passlen, ntpass, ntpasslen,
648                                      workgroup);        
649 }
650
651 /****************************************************************************
652  Send a uloggoff.
653 *****************************************************************************/
654
655 BOOL cli_ulogoff(struct cli_state *cli)
656 {
657         memset(cli->outbuf,'\0',smb_size);
658         set_message(cli->outbuf,2,0,True);
659         SCVAL(cli->outbuf,smb_com,SMBulogoffX);
660         cli_setup_packet(cli);
661         SSVAL(cli->outbuf,smb_vwv0,0xFF);
662         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
663
664         cli_send_smb(cli);
665         if (!cli_receive_smb(cli))
666                 return False;
667
668         return !cli_is_error(cli);
669 }
670
671 /****************************************************************************
672  Send a tconX.
673 ****************************************************************************/
674
675 BOOL cli_send_tconX(struct cli_state *cli, 
676                     const char *share, const char *dev, const char *pass, int passlen)
677 {
678         fstring fullshare, pword;
679         char *p;
680         memset(cli->outbuf,'\0',smb_size);
681         memset(cli->inbuf,'\0',smb_size);
682
683         fstrcpy(cli->share, share);
684
685         /* in user level security don't send a password now */
686         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
687                 passlen = 1;
688                 pass = "";
689         }
690
691         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
692                 /*
693                  * Non-encrypted passwords - convert to DOS codepage before encryption.
694                  */
695                 passlen = 24;
696                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
697         } else {
698                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
699                         /*
700                          * Non-encrypted passwords - convert to DOS codepage before using.
701                          */
702                         passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
703                 } else {
704                         memcpy(pword, pass, passlen);
705                 }
706         }
707
708         if (cli->port == 445) {
709                 slprintf(fullshare, sizeof(fullshare)-1,
710                          "%s", share);
711         } else {
712                 slprintf(fullshare, sizeof(fullshare)-1,
713                          "\\\\%s\\%s", cli->desthost, share);
714         }
715
716         set_message(cli->outbuf,4, 0, True);
717         SCVAL(cli->outbuf,smb_com,SMBtconX);
718         cli_setup_packet(cli);
719
720         SSVAL(cli->outbuf,smb_vwv0,0xFF);
721         SSVAL(cli->outbuf,smb_vwv3,passlen);
722
723         p = smb_buf(cli->outbuf);
724         memcpy(p,pword,passlen);
725         p += passlen;
726         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
727         fstrcpy(p, dev); p += strlen(dev)+1;
728
729         cli_setup_bcc(cli, p);
730
731         cli_send_smb(cli);
732         if (!cli_receive_smb(cli))
733                 return False;
734
735         if (cli_is_error(cli)) {
736                 return False;
737         }
738
739         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
740
741         if (strcasecmp(share,"IPC$")==0) {
742                 fstrcpy(cli->dev, "IPC");
743         }
744
745         if (cli->protocol >= PROTOCOL_NT1 &&
746             smb_buflen(cli->inbuf) == 3) {
747                 /* almost certainly win95 - enable bug fixes */
748                 cli->win95 = True;
749         }
750
751         cli->cnum = SVAL(cli->inbuf,smb_tid);
752         return True;
753 }
754
755 /****************************************************************************
756  Send a tree disconnect.
757 ****************************************************************************/
758
759 BOOL cli_tdis(struct cli_state *cli)
760 {
761         memset(cli->outbuf,'\0',smb_size);
762         set_message(cli->outbuf,0,0,True);
763         SCVAL(cli->outbuf,smb_com,SMBtdis);
764         SSVAL(cli->outbuf,smb_tid,cli->cnum);
765         cli_setup_packet(cli);
766         
767         cli_send_smb(cli);
768         if (!cli_receive_smb(cli))
769                 return False;
770         
771         return !cli_is_error(cli);
772 }
773
774 /****************************************************************************
775  Send a negprot command.
776 ****************************************************************************/
777
778 void cli_negprot_send(struct cli_state *cli)
779 {
780         char *p;
781         int numprots;
782
783         if (cli->protocol < PROTOCOL_NT1) {
784                 cli->use_spnego = False;
785         }
786
787         memset(cli->outbuf,'\0',smb_size);
788
789         /* setup the protocol strings */
790         set_message(cli->outbuf,0,0,True);
791
792         p = smb_buf(cli->outbuf);
793         for (numprots=0;
794              prots[numprots].name && prots[numprots].prot<=cli->protocol;
795              numprots++) {
796                 *p++ = 2;
797                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
798         }
799
800         SCVAL(cli->outbuf,smb_com,SMBnegprot);
801         cli_setup_bcc(cli, p);
802         cli_setup_packet(cli);
803
804         SCVAL(smb_buf(cli->outbuf),0,2);
805
806         cli_send_smb(cli);
807 }
808
809 /****************************************************************************
810  Send a negprot command.
811 ****************************************************************************/
812
813 BOOL cli_negprot(struct cli_state *cli)
814 {
815         char *p;
816         int numprots;
817         int plength;
818
819         if (cli->sign_info.use_smb_signing) {
820                 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
821                 return False;
822         }
823
824         if (cli->protocol < PROTOCOL_NT1) {
825                 cli->use_spnego = False;
826         }
827
828 #if 1 /* JRA SIGN TEST */
829         cli->use_spnego = False;
830 #endif
831
832         memset(cli->outbuf,'\0',smb_size);
833
834         /* setup the protocol strings */
835         for (plength=0,numprots=0;
836              prots[numprots].name && prots[numprots].prot<=cli->protocol;
837              numprots++)
838                 plength += strlen(prots[numprots].name)+2;
839     
840         set_message(cli->outbuf,0,plength,True);
841
842         p = smb_buf(cli->outbuf);
843         for (numprots=0;
844              prots[numprots].name && prots[numprots].prot<=cli->protocol;
845              numprots++) {
846                 *p++ = 2;
847                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
848         }
849
850         SCVAL(cli->outbuf,smb_com,SMBnegprot);
851         cli_setup_packet(cli);
852
853         SCVAL(smb_buf(cli->outbuf),0,2);
854
855         cli_send_smb(cli);
856         if (!cli_receive_smb(cli))
857                 return False;
858
859         show_msg(cli->inbuf);
860
861         if (cli_is_error(cli) ||
862             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
863                 return(False);
864         }
865
866         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
867
868         if (cli->protocol >= PROTOCOL_NT1) {    
869                 /* NT protocol */
870                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
871                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
872                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
873                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
874                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
875                 cli->serverzone *= 60;
876                 /* this time arrives in real GMT */
877                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
878                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
879                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
880                 if (cli->capabilities & CAP_RAW_MODE) {
881                         cli->readbraw_supported = True;
882                         cli->writebraw_supported = True;      
883                 }
884                 /* work out if they sent us a workgroup */
885                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
886                     smb_buflen(cli->inbuf) > 8) {
887                         clistr_pull(cli, cli->server_domain, 
888                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
889                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
890                 }
891
892                 /* A way to attempt to force SMB signing */
893                 if (getenv("CLI_FORCE_SMB_SIGNING"))
894                         cli->sign_info.negotiated_smb_signing = True;
895                                    
896 #if 0
897                 if (cli->sign_info.negotiated_smb_signing && !(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
898                         cli->sign_info.negotiated_smb_signing = False;
899 #endif
900
901         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
902                 cli->use_spnego = False;
903                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
904                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
905                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
906                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
907                 cli->serverzone *= 60;
908                 /* this time is converted to GMT by make_unix_date */
909                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
910                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
911                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
912                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
913         } else {
914                 /* the old core protocol */
915                 cli->use_spnego = False;
916                 cli->sec_mode = 0;
917                 cli->serverzone = TimeDiff(time(NULL));
918         }
919
920         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
921
922         /* a way to force ascii SMB */
923         if (getenv("CLI_FORCE_ASCII")) {
924                 cli->capabilities &= ~CAP_UNICODE;
925         }
926
927         return True;
928 }
929
930 /****************************************************************************
931  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
932 ****************************************************************************/
933
934 BOOL cli_session_request(struct cli_state *cli,
935                          struct nmb_name *calling, struct nmb_name *called)
936 {
937         char *p;
938         int len = 4;
939         extern pstring user_socket_options;
940
941         /* 445 doesn't have session request */
942         if (cli->port == 445) return True;
943
944         if (cli->sign_info.use_smb_signing) {
945                 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
946                 return False;
947         }
948
949         /* send a session request (RFC 1002) */
950         memcpy(&(cli->calling), calling, sizeof(*calling));
951         memcpy(&(cli->called ), called , sizeof(*called ));
952   
953         /* put in the destination name */
954         p = cli->outbuf+len;
955         name_mangle(cli->called .name, p, cli->called .name_type);
956         len += name_len(p);
957
958         /* and my name */
959         p = cli->outbuf+len;
960         name_mangle(cli->calling.name, p, cli->calling.name_type);
961         len += name_len(p);
962
963         /* setup the packet length */
964         _smb_setlen(cli->outbuf,len);
965         SCVAL(cli->outbuf,0,0x81);
966
967         cli_send_smb(cli);
968         DEBUG(5,("Sent session request\n"));
969
970         if (!cli_receive_smb(cli))
971                 return False;
972
973         if (CVAL(cli->inbuf,0) == 0x84) {
974                 /* C. Hoch  9/14/95 Start */
975                 /* For information, here is the response structure.
976                  * We do the byte-twiddling to for portability.
977                 struct RetargetResponse{
978                 unsigned char type;
979                 unsigned char flags;
980                 int16 length;
981                 int32 ip_addr;
982                 int16 port;
983                 };
984                 */
985                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
986                 /* SESSION RETARGET */
987                 putip((char *)&cli->dest_ip,cli->inbuf+4);
988
989                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
990                 if (cli->fd == -1)
991                         return False;
992
993                 DEBUG(3,("Retargeted\n"));
994
995                 set_socket_options(cli->fd,user_socket_options);
996
997                 /* Try again */
998                 {
999                         static int depth;
1000                         BOOL ret;
1001                         if (depth > 4) {
1002                                 DEBUG(0,("Retarget recursion - failing\n"));
1003                                 return False;
1004                         }
1005                         depth++;
1006                         ret = cli_session_request(cli, calling, called);
1007                         depth--;
1008                         return ret;
1009                 }
1010         } /* C. Hoch 9/14/95 End */
1011
1012         if (CVAL(cli->inbuf,0) != 0x82) {
1013                 /* This is the wrong place to put the error... JRA. */
1014                 cli->rap_error = CVAL(cli->inbuf,4);
1015                 return False;
1016         }
1017         return(True);
1018 }
1019
1020 /****************************************************************************
1021  Open the client sockets.
1022 ****************************************************************************/
1023
1024 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1025 {
1026         extern pstring user_socket_options;
1027         int name_type = 0x20;
1028         char *p;
1029
1030         /* reasonable default hostname */
1031         if (!host) host = "*SMBSERVER";
1032
1033         fstrcpy(cli->desthost, host);
1034
1035         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1036         if ((p = strchr(cli->desthost, '#'))) {
1037                 name_type = strtol(p+1, NULL, 16);              
1038                 *p = 0;
1039         }
1040         
1041         if (!ip || is_zero_ip(*ip)) {
1042                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1043                         return False;
1044                 }
1045                 if (ip) *ip = cli->dest_ip;
1046         } else {
1047                 cli->dest_ip = *ip;
1048         }
1049
1050         if (getenv("LIBSMB_PROG")) {
1051                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1052         } else {
1053                 /* try 445 first, then 139 */
1054                 int port = cli->port?cli->port:445;
1055                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1056                                           port, cli->timeout);
1057                 if (cli->fd == -1 && cli->port == 0) {
1058                         port = 139;
1059                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1060                                                   port, cli->timeout);
1061                 }
1062                 if (cli->fd != -1) cli->port = port;
1063         }
1064         if (cli->fd == -1) {
1065                 DEBUG(1,("Error connecting to %s (%s)\n",
1066                          inet_ntoa(*ip),strerror(errno)));
1067                 return False;
1068         }
1069
1070         set_socket_options(cli->fd,user_socket_options);
1071
1072         return True;
1073 }
1074
1075 /****************************************************************************
1076  Initialise client credentials for authenticated pipe access.
1077 ****************************************************************************/
1078
1079 static void init_creds(struct ntuser_creds *creds, char* username,
1080                        char* domain, char* password)
1081 {
1082         ZERO_STRUCTP(creds);
1083
1084         pwd_set_cleartext(&creds->pwd, password);
1085
1086         fstrcpy(creds->user_name, username);
1087         fstrcpy(creds->domain, domain);
1088
1089         if (!*username) {
1090                 creds->pwd.null_pwd = True;
1091         }
1092 }
1093
1094 /**
1095    establishes a connection right up to doing tconX, password specified.
1096    @param output_cli A fully initialised cli structure, non-null only on success
1097    @param dest_host The netbios name of the remote host
1098    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1099    @param port (optional) The destination port (0 for default)
1100    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1101    @param service_type The 'type' of serivice. 
1102    @param user Username, unix string
1103    @param domain User's domain
1104    @param password User's password, unencrypted unix string.
1105 */
1106
1107 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1108                              const char *my_name, 
1109                              const char *dest_host, 
1110                              struct in_addr *dest_ip, int port,
1111                              char *service, char *service_type,
1112                              char *user, char *domain, 
1113                              char *password, int flags) 
1114 {
1115         struct ntuser_creds creds;
1116         NTSTATUS nt_status;
1117         struct nmb_name calling;
1118         struct nmb_name called;
1119         struct cli_state *cli;
1120         struct in_addr ip;
1121         extern pstring global_myname;
1122
1123         if (!output_cli) {
1124                 DEBUG(0, ("output_cli is NULL!?!"));
1125                 SMB_ASSERT("output_cli for cli_full_connection was NULL.\n");
1126         }
1127
1128         if (!my_name) 
1129                 my_name = global_myname;
1130         
1131         if (!(cli = cli_initialise(NULL)))
1132                 return NT_STATUS_NO_MEMORY;
1133         
1134         make_nmb_name(&calling, my_name, 0x0);
1135         make_nmb_name(&called , dest_host, 0x20);
1136
1137         if (cli_set_port(cli, port) != port) {
1138                 cli_shutdown(cli);
1139                 return NT_STATUS_UNSUCCESSFUL;
1140         }
1141
1142         if (dest_ip) {
1143                 ip = *dest_ip;
1144         } else {
1145                 ZERO_STRUCT(ip);
1146         }
1147
1148 again:
1149
1150         DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1151         
1152         if (!cli_connect(cli, dest_host, &ip)) {
1153                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1154                          nmb_namestr(&called), inet_ntoa(ip)));
1155                 cli_shutdown(cli);
1156                 return NT_STATUS_UNSUCCESSFUL;
1157         }
1158
1159         if (!cli_session_request(cli, &calling, &called)) {
1160                 char *p;
1161                 DEBUG(1,("session request to %s failed (%s)\n", 
1162                          called.name, cli_errstr(cli)));
1163                 cli_shutdown(cli);
1164                 if ((p=strchr(called.name, '.'))) {
1165                         *p = 0;
1166                         goto again;
1167                 }
1168                 if (strcmp(called.name, "*SMBSERVER")) {
1169                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1170                         goto again;
1171                 }
1172                 return NT_STATUS_UNSUCCESSFUL;
1173         }
1174
1175         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
1176                 cli->use_spnego = False;
1177         } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
1178                 cli->use_kerberos = True;
1179         }
1180
1181         if (!cli_negprot(cli)) {
1182                 DEBUG(1,("failed negprot\n"));
1183                 nt_status = NT_STATUS_UNSUCCESSFUL;
1184                 cli_shutdown(cli);
1185                 return nt_status;
1186         }
1187
1188         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1189                                password, strlen(password)+1, 
1190                                domain)) {
1191                 if (!(flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK) 
1192                     || cli_session_setup(cli, "", "", 0, 
1193                                          "", 0, domain)) {
1194                 } else {
1195                         nt_status = cli_nt_error(cli);
1196                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1197                         cli_shutdown(cli);
1198                         if (NT_STATUS_IS_OK(nt_status)) 
1199                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1200                         return nt_status;
1201                 }
1202         } 
1203
1204         if (service) {
1205                 if (!cli_send_tconX(cli, service, service_type,
1206                                     (char*)password, strlen(password)+1)) {
1207                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1208                         nt_status = cli_nt_error(cli);
1209                         cli_shutdown(cli);
1210                         if (NT_STATUS_IS_OK(nt_status)) {
1211                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1212                         }
1213                         return nt_status;
1214                 }
1215         }
1216
1217         init_creds(&creds, user, domain, password);
1218         cli_init_creds(cli, &creds);
1219
1220         *output_cli = cli;
1221         return NT_STATUS_OK;
1222 }
1223
1224 /****************************************************************************
1225  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1226 ****************************************************************************/
1227
1228 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1229                                      struct in_addr *pdest_ip)
1230 {
1231         struct nmb_name calling, called;
1232
1233         make_nmb_name(&calling, srchost, 0x0);
1234
1235         /*
1236          * If the called name is an IP address
1237          * then use *SMBSERVER immediately.
1238          */
1239
1240         if(is_ipaddress(desthost))
1241                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1242         else
1243                 make_nmb_name(&called, desthost, 0x20);
1244
1245         if (!cli_session_request(cli, &calling, &called)) {
1246                 struct nmb_name smbservername;
1247
1248                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1249
1250                 /*
1251                  * If the name wasn't *SMBSERVER then
1252                  * try with *SMBSERVER if the first name fails.
1253                  */
1254
1255                 if (nmb_name_equal(&called, &smbservername)) {
1256
1257                         /*
1258                          * The name used was *SMBSERVER, don't bother with another name.
1259                          */
1260
1261                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1262 with error %s.\n", desthost, cli_errstr(cli) ));
1263                         cli_shutdown(cli);
1264                         return False;
1265                 }
1266
1267                 cli_shutdown(cli);
1268
1269                 if (!cli_initialise(cli) ||
1270                                 !cli_connect(cli, desthost, pdest_ip) ||
1271                                 !cli_session_request(cli, &calling, &smbservername)) {
1272                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1273 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1274                         cli_shutdown(cli);
1275                         return False;
1276                 }
1277         }
1278
1279         return True;
1280 }