Fix #442 which Alexander considered a showstopper. Allow us to join mixed
[samba.git] / source / 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 Bartlett 2001-2003
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, const char *user, 
48                                       const char *pass, size_t passlen, const char *workgroup)
49 {
50         fstring pword;
51         char *p;
52
53         if (passlen > sizeof(pword)-1)
54                 return False;
55
56         /* if in share level security then don't send a password now */
57         if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
58                 passlen = 0;
59
60         if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
61                 /* Encrypted mode needed, and non encrypted password supplied. */
62                 passlen = 24;
63                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
64         } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
65                 /* Encrypted mode needed, and encrypted password supplied. */
66                 memcpy(pword, pass, passlen);
67         } else if (passlen > 0) {
68                 /* Plaintext mode needed, assume plaintext supplied. */
69                 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
70         }
71
72         /* send a session setup command */
73         memset(cli->outbuf,'\0',smb_size);
74         set_message(cli->outbuf,10, 0, True);
75         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
76         cli_setup_packet(cli);
77         
78         SCVAL(cli->outbuf,smb_vwv0,0xFF);
79         SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
80         SSVAL(cli->outbuf,smb_vwv3,2);
81         SSVAL(cli->outbuf,smb_vwv4,1);
82         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
83         SSVAL(cli->outbuf,smb_vwv7,passlen);
84
85         p = smb_buf(cli->outbuf);
86         memcpy(p,pword,passlen);
87         p += passlen;
88         p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
89         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
90         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
91         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
92         cli_setup_bcc(cli, p);
93
94         cli_send_smb(cli);
95         if (!cli_receive_smb(cli))
96                 return False;
97
98         show_msg(cli->inbuf);
99
100         if (cli_is_error(cli))
101                 return False;
102         
103         /* use the returned vuid from now on */
104         cli->vuid = SVAL(cli->inbuf,smb_uid);   
105         fstrcpy(cli->user_name, user);
106
107         return True;
108 }
109
110 /****************************************************************************
111  Work out suitable capabilities to offer the server.
112 ****************************************************************************/
113
114 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
115 {
116         uint32 capabilities = CAP_NT_SMBS;
117
118         if (!cli->force_dos_errors)
119                 capabilities |= CAP_STATUS32;
120
121         if (cli->use_level_II_oplocks)
122                 capabilities |= CAP_LEVEL_II_OPLOCKS;
123
124         if (cli->capabilities & CAP_UNICODE)
125                 capabilities |= CAP_UNICODE;
126
127         if (cli->capabilities & CAP_LARGE_FILES)
128                 capabilities |= CAP_LARGE_FILES;
129
130         return capabilities;
131 }
132
133 /****************************************************************************
134  Do a NT1 guest session setup.
135 ****************************************************************************/
136
137 static BOOL cli_session_setup_guest(struct cli_state *cli)
138 {
139         char *p;
140         uint32 capabilities = cli_session_setup_capabilities(cli);
141
142         set_message(cli->outbuf,13,0,True);
143         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
144         cli_setup_packet(cli);
145                         
146         SCVAL(cli->outbuf,smb_vwv0,0xFF);
147         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
148         SSVAL(cli->outbuf,smb_vwv3,2);
149         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
150         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
151         SSVAL(cli->outbuf,smb_vwv7,0);
152         SSVAL(cli->outbuf,smb_vwv8,0);
153         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
154         p = smb_buf(cli->outbuf);
155         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
156         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
157         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
158         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
159         cli_setup_bcc(cli, p);
160
161         cli_send_smb(cli);
162         if (!cli_receive_smb(cli))
163               return False;
164         
165         show_msg(cli->inbuf);
166         
167         if (cli_is_error(cli))
168                 return False;
169
170         cli->vuid = SVAL(cli->inbuf,smb_uid);
171
172         p = smb_buf(cli->inbuf);
173         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
174         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
175         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
176
177         fstrcpy(cli->user_name, "");
178
179         return True;
180 }
181
182 /****************************************************************************
183  Do a NT1 plaintext session setup.
184 ****************************************************************************/
185
186 static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user, 
187                                         const char *pass, const char *workgroup)
188 {
189         uint32 capabilities = cli_session_setup_capabilities(cli);
190         char *p;
191         fstring lanman;
192         
193         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
194
195         set_message(cli->outbuf,13,0,True);
196         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
197         cli_setup_packet(cli);
198                         
199         SCVAL(cli->outbuf,smb_vwv0,0xFF);
200         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
201         SSVAL(cli->outbuf,smb_vwv3,2);
202         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
203         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
204         SSVAL(cli->outbuf,smb_vwv8,0);
205         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
206         p = smb_buf(cli->outbuf);
207         
208         /* check wether to send the ASCII or UNICODE version of the password */
209         
210         if ( (capabilities & CAP_UNICODE) == 0 ) {
211                 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
212                 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
213         }
214         else { 
215                 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
216                 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf)));  
217         }
218         
219         p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
220         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
221         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
222         p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
223         cli_setup_bcc(cli, p);
224
225         cli_send_smb(cli);
226         if (!cli_receive_smb(cli))
227               return False;
228         
229         show_msg(cli->inbuf);
230         
231         if (cli_is_error(cli))
232                 return False;
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 static void set_cli_session_key (struct cli_state *cli, DATA_BLOB session_key) 
245 {
246         memcpy(cli->user_session_key, session_key.data, MIN(session_key.length, sizeof(cli->user_session_key)));
247 }
248
249 /****************************************************************************
250    do a NT1 NTLM/LM encrypted session setup - for when extended security
251    is not negotiated.
252    @param cli client state to create do session setup on
253    @param user username
254    @param pass *either* cleartext password (passlen !=24) or LM response.
255    @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
256    @param workgroup The user's domain.
257 ****************************************************************************/
258
259 static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, 
260                                   const char *pass, size_t passlen,
261                                   const char *ntpass, size_t ntpasslen,
262                                   const char *workgroup)
263 {
264         uint32 capabilities = cli_session_setup_capabilities(cli);
265         DATA_BLOB lm_response = data_blob(NULL, 0);
266         DATA_BLOB nt_response = data_blob(NULL, 0);
267         DATA_BLOB session_key = data_blob(NULL, 0);
268         BOOL ret = False;
269         char *p;
270
271         if (passlen == 0) {
272                 /* do nothing - guest login */
273         } else if (passlen != 24) {
274                 if (lp_client_ntlmv2_auth()) {
275                         DATA_BLOB server_chal;
276                         DATA_BLOB names_blob;
277                         server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8)); 
278
279                         /* note that the 'workgroup' here is a best guess - we don't know
280                            the server's domain at this point.  The 'server name' is also
281                            dodgy... 
282                         */
283                         names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
284
285                         if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal, 
286                                               &names_blob,
287                                               &lm_response, &nt_response, &session_key)) {
288                                 data_blob_free(&names_blob);
289                                 data_blob_free(&server_chal);
290                                 return False;
291                         }
292                         data_blob_free(&names_blob);
293                         data_blob_free(&server_chal);
294
295                 } else {
296                         uchar nt_hash[16];
297                         E_md4hash(pass, nt_hash);
298
299                         nt_response = data_blob(NULL, 24);
300                         SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
301
302                         /* non encrypted password supplied. Ignore ntpass. */
303                         if (lp_client_lanman_auth()) {
304                                 lm_response = data_blob(NULL, 24);
305                                 SMBencrypt(pass,cli->secblob.data, lm_response.data);
306                         } else {
307                                 /* LM disabled, place NT# in LM field instead */
308                                 lm_response = data_blob(nt_response.data, nt_response.length);
309                         }
310
311                         session_key = data_blob(NULL, 16);
312                         SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
313                 }
314                 cli_simple_set_signing(cli, session_key.data, nt_response); 
315         } else {
316                 /* pre-encrypted password supplied.  Only used for 
317                    security=server, can't do
318                    signing because we don't have original key */
319
320                 lm_response = data_blob(pass, passlen);
321                 nt_response = data_blob(ntpass, ntpasslen);
322         }
323
324         /* send a session setup command */
325         memset(cli->outbuf,'\0',smb_size);
326
327         set_message(cli->outbuf,13,0,True);
328         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
329         cli_setup_packet(cli);
330                         
331         SCVAL(cli->outbuf,smb_vwv0,0xFF);
332         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
333         SSVAL(cli->outbuf,smb_vwv3,2);
334         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
335         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
336         SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
337         SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
338         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
339         p = smb_buf(cli->outbuf);
340         if (lm_response.length) {
341                 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
342         }
343         if (nt_response.length) {
344                 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
345         }
346         p += clistr_push(cli, p, user, -1, STR_TERMINATE);
347         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE);
348         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
349         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
350         cli_setup_bcc(cli, p);
351
352         if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
353                 ret = False;
354                 goto end;
355         }
356
357         /* show_msg(cli->inbuf); */
358
359         if (cli_is_error(cli)) {
360                 ret = False;
361                 goto end;
362         }
363
364         /* use the returned vuid from now on */
365         cli->vuid = SVAL(cli->inbuf,smb_uid);
366         
367         p = smb_buf(cli->inbuf);
368         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
369         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
370         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
371
372         fstrcpy(cli->user_name, user);
373
374         if (session_key.data) {
375                 /* Have plaintext orginal */
376                 set_cli_session_key(cli, session_key);
377         }
378
379         ret = True;
380 end:    
381         data_blob_free(&lm_response);
382         data_blob_free(&nt_response);
383         data_blob_free(&session_key);
384         return ret;
385 }
386
387 /****************************************************************************
388  Send a extended security session setup blob
389 ****************************************************************************/
390
391 static BOOL cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
392 {
393         uint32 capabilities = cli_session_setup_capabilities(cli);
394         char *p;
395
396         capabilities |= CAP_EXTENDED_SECURITY;
397
398         /* send a session setup command */
399         memset(cli->outbuf,'\0',smb_size);
400
401         set_message(cli->outbuf,12,0,True);
402         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
403
404         cli_setup_packet(cli);
405                         
406         SCVAL(cli->outbuf,smb_vwv0,0xFF);
407         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
408         SSVAL(cli->outbuf,smb_vwv3,2);
409         SSVAL(cli->outbuf,smb_vwv4,1);
410         SIVAL(cli->outbuf,smb_vwv5,0);
411         SSVAL(cli->outbuf,smb_vwv7,blob.length);
412         SIVAL(cli->outbuf,smb_vwv10,capabilities); 
413         p = smb_buf(cli->outbuf);
414         memcpy(p, blob.data, blob.length);
415         p += blob.length;
416         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
417         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
418         cli_setup_bcc(cli, p);
419         return cli_send_smb(cli);
420 }
421
422 /****************************************************************************
423  Send a extended security session setup blob, returning a reply blob.
424 ****************************************************************************/
425
426 static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
427 {
428         DATA_BLOB blob2 = data_blob(NULL, 0);
429         char *p;
430         size_t len;
431
432         if (!cli_receive_smb(cli))
433                 return blob2;
434
435         show_msg(cli->inbuf);
436
437         if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
438                                                   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
439                 return blob2;
440         }
441         
442         /* use the returned vuid from now on */
443         cli->vuid = SVAL(cli->inbuf,smb_uid);
444         
445         p = smb_buf(cli->inbuf);
446
447         blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
448
449         p += blob2.length;
450         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
451
452         /* w2k with kerberos doesn't properly null terminate this field */
453         len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
454         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
455
456         return blob2;
457 }
458
459 #ifdef HAVE_KRB5
460
461 /****************************************************************************
462  Send a extended security session setup blob, returning a reply blob.
463 ****************************************************************************/
464
465 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
466 {
467         DATA_BLOB blob2 = data_blob(NULL, 0);
468         if (!cli_session_setup_blob_send(cli, blob)) {
469                 return blob2;
470         }
471                 
472         return cli_session_setup_blob_receive(cli);
473 }
474
475 /****************************************************************************
476  Use in-memory credentials cache
477 ****************************************************************************/
478
479 static void use_in_memory_ccache(void) {
480         setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
481 }
482
483 /****************************************************************************
484  Do a spnego/kerberos encrypted session setup.
485 ****************************************************************************/
486
487 static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
488 {
489         DATA_BLOB blob2, negTokenTarg;
490         unsigned char session_key_krb5[16];
491         DATA_BLOB null_blob = data_blob(NULL, 0);
492         
493         DEBUG(2,("Doing kerberos session setup\n"));
494
495         /* generate the encapsulated kerberos5 ticket */
496         negTokenTarg = spnego_gen_negTokenTarg(principal, 0, session_key_krb5);
497
498         if (!negTokenTarg.data)
499                 return False;
500
501 #if 0
502         file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
503 #endif
504
505         cli_simple_set_signing(cli, session_key_krb5, null_blob); 
506                         
507         blob2 = cli_session_setup_blob(cli, negTokenTarg);
508
509         /* we don't need this blob for kerberos */
510         data_blob_free(&blob2);
511
512         data_blob_free(&negTokenTarg);
513
514         return !cli_is_error(cli);
515 }
516 #endif  /* HAVE_KRB5 */
517
518
519 /****************************************************************************
520  Do a spnego/NTLMSSP encrypted session setup.
521 ****************************************************************************/
522
523 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, 
524                                       const char *pass, const char *workgroup)
525 {
526         struct ntlmssp_client_state *ntlmssp_state;
527         NTSTATUS nt_status;
528         int turn = 1;
529         DATA_BLOB msg1;
530         DATA_BLOB blob;
531         DATA_BLOB blob_in = data_blob(NULL, 0);
532         DATA_BLOB blob_out;
533
534         cli_temp_set_signing(cli);
535
536         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
537                 return False;
538         }
539
540         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
541                 return False;
542         }
543         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, workgroup))) {
544                 return False;
545         }
546         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
547                 return False;
548         }
549
550         do {
551                 nt_status = ntlmssp_client_update(ntlmssp_state, 
552                                                   blob_in, &blob_out);
553                 data_blob_free(&blob_in);
554                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
555                         DATA_BLOB null_blob = data_blob(NULL, 0);
556                         if (turn == 1) {
557                                 /* and wrap it in a SPNEGO wrapper */
558                                 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
559                         } else {
560                                 /* wrap it in SPNEGO */
561                                 msg1 = spnego_gen_auth(blob_out);
562                         }
563                 
564                         cli_simple_set_signing(cli, 
565                                                ntlmssp_state->session_key.data, 
566                                                null_blob); 
567                         
568                         /* now send that blob on its way */
569                         if (!cli_session_setup_blob_send(cli, msg1)) {
570                                 return False;
571                         }
572                         data_blob_free(&msg1);
573                         
574                         blob = cli_session_setup_blob_receive(cli);
575
576                         nt_status = cli_nt_error(cli);
577                 }
578                 
579                 if (!blob.length) {
580                         if (NT_STATUS_IS_OK(nt_status)) {
581                                 nt_status = NT_STATUS_UNSUCCESSFUL;
582                         }
583                 } else if ((turn == 1) && 
584                            NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
585                         DATA_BLOB tmp_blob = data_blob(NULL, 0);
586                         /* the server might give us back two challenges */
587                         if (!spnego_parse_challenge(blob, &blob_in, 
588                                                     &tmp_blob)) {
589                                 DEBUG(3,("Failed to parse challenges\n"));
590                                 nt_status = NT_STATUS_INVALID_PARAMETER;
591                         }
592                         data_blob_free(&tmp_blob);
593                 } else {
594                         if (!spnego_parse_auth_response(blob, nt_status, 
595                                                         &blob_in)) {
596                                 DEBUG(3,("Failed to parse auth response\n"));
597                                 if (NT_STATUS_IS_OK(nt_status) 
598                                     || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) 
599                                         nt_status = NT_STATUS_INVALID_PARAMETER;
600                         }
601                 }
602                 data_blob_free(&blob);
603                 data_blob_free(&blob_out);
604                 turn++;
605         } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
606
607         if (NT_STATUS_IS_OK(nt_status)) {
608                 fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
609                 set_cli_session_key(cli, ntlmssp_state->session_key);
610         }
611
612         /* we have a reference conter on ntlmssp_state, if we are signing
613            then the state will be kept by the signing engine */
614
615         if (!NT_STATUS_IS_OK(ntlmssp_client_end(&ntlmssp_state))) {
616                 return False;
617         }
618         
619         return (NT_STATUS_IS_OK(nt_status));
620 }
621
622 /****************************************************************************
623  Do a spnego encrypted session setup.
624 ****************************************************************************/
625
626 BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user, 
627                               const char *pass, const char *workgroup)
628 {
629         char *principal;
630         char *OIDs[ASN1_MAX_OIDS];
631         int i;
632         BOOL got_kerberos_mechanism = False;
633         DATA_BLOB blob;
634
635         DEBUG(2,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
636
637         /* the server might not even do spnego */
638         if (cli->secblob.length <= 16) {
639                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
640                 goto ntlmssp;
641         }
642
643 #if 0
644         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
645 #endif
646
647         /* there is 16 bytes of GUID before the real spnego packet starts */
648         blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
649
650         /* the server sent us the first part of the SPNEGO exchange in the negprot 
651            reply */
652         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
653                 data_blob_free(&blob);
654                 return False;
655         }
656         data_blob_free(&blob);
657
658         /* make sure the server understands kerberos */
659         for (i=0;OIDs[i];i++) {
660                 DEBUG(3,("got OID=%s\n", OIDs[i]));
661                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
662                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
663                         got_kerberos_mechanism = True;
664                 }
665                 free(OIDs[i]);
666         }
667         DEBUG(3,("got principal=%s\n", principal));
668
669         fstrcpy(cli->user_name, user);
670
671 #ifdef HAVE_KRB5
672         /* If password is set we reauthenticate to kerberos server
673          * and do not store results */
674
675         if (got_kerberos_mechanism && cli->use_kerberos) {
676                 if (pass && *pass) {
677                         int ret;
678                         
679                         use_in_memory_ccache();
680                         ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */);
681                         
682                         if (ret){
683                                 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
684                                 return False;
685                         }
686                 }
687                 
688                 return cli_session_setup_kerberos(cli, principal, workgroup);
689         }
690 #endif
691
692         free(principal);
693
694 ntlmssp:
695
696         return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
697 }
698
699 /****************************************************************************
700  Send a session setup. The username and workgroup is in UNIX character
701  format and must be converted to DOS codepage format before sending. If the
702  password is in plaintext, the same should be done.
703 ****************************************************************************/
704
705 BOOL cli_session_setup(struct cli_state *cli, 
706                        const char *user, 
707                        const char *pass, int passlen,
708                        const char *ntpass, int ntpasslen,
709                        const char *workgroup)
710 {
711         char *p;
712         fstring user2;
713
714         /* allow for workgroups as part of the username */
715         fstrcpy(user2, user);
716         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
717             (p=strchr_m(user2,*lp_winbind_separator()))) {
718                 *p = 0;
719                 user = p+1;
720                 workgroup = user2;
721         }
722
723         if (cli->protocol < PROTOCOL_LANMAN1)
724                 return True;
725
726         /* now work out what sort of session setup we are going to
727            do. I have split this into separate functions to make the
728            flow a bit easier to understand (tridge) */
729
730         /* if its an older server then we have to use the older request format */
731
732         if (cli->protocol < PROTOCOL_NT1) {
733                 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
734                         DEBUG(1, ("Server requested LM password but 'client lanman auth'"
735                                   " is disabled\n"));
736                         return False;
737                 }
738
739                 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
740                     !lp_client_plaintext_auth() && (*pass)) {
741                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
742                                   " is disabled\n"));
743                         return False;
744                 }
745
746                 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
747         }
748
749         /* if no user is supplied then we have to do an anonymous connection.
750            passwords are ignored */
751
752         if (!user || !*user)
753                 return cli_session_setup_guest(cli);
754
755         /* if the server is share level then send a plaintext null
756            password at this point. The password is sent in the tree
757            connect */
758
759         if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) 
760                 return cli_session_setup_plaintext(cli, user, "", workgroup);
761
762         /* if the server doesn't support encryption then we have to use 
763            plaintext. The second password is ignored */
764
765         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
766                 if (!lp_client_plaintext_auth() && (*pass)) {
767                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
768                                   " is disabled\n"));
769                         return False;
770                 }
771                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
772         }
773
774         /* if the server supports extended security then use SPNEGO */
775
776         if (cli->capabilities & CAP_EXTENDED_SECURITY)
777                 return cli_session_setup_spnego(cli, user, pass, workgroup);
778
779         /* otherwise do a NT1 style session setup */
780
781         return cli_session_setup_nt1(cli, user, 
782                                      pass, passlen, ntpass, ntpasslen,
783                                      workgroup);        
784 }
785
786 /****************************************************************************
787  Send a uloggoff.
788 *****************************************************************************/
789
790 BOOL cli_ulogoff(struct cli_state *cli)
791 {
792         memset(cli->outbuf,'\0',smb_size);
793         set_message(cli->outbuf,2,0,True);
794         SCVAL(cli->outbuf,smb_com,SMBulogoffX);
795         cli_setup_packet(cli);
796         SSVAL(cli->outbuf,smb_vwv0,0xFF);
797         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
798
799         cli_send_smb(cli);
800         if (!cli_receive_smb(cli))
801                 return False;
802
803         return !cli_is_error(cli);
804 }
805
806 /****************************************************************************
807  Send a tconX.
808 ****************************************************************************/
809 BOOL cli_send_tconX(struct cli_state *cli, 
810                     const char *share, const char *dev, const char *pass, int passlen)
811 {
812         fstring fullshare, pword;
813         char *p;
814         memset(cli->outbuf,'\0',smb_size);
815         memset(cli->inbuf,'\0',smb_size);
816
817         fstrcpy(cli->share, share);
818
819         /* in user level security don't send a password now */
820         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
821                 passlen = 1;
822                 pass = "";
823         }
824
825         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
826                 if (!lp_client_lanman_auth()) {
827                         DEBUG(1, ("Server requested LANMAN password but 'client use lanman auth'"
828                                   " is disabled\n"));
829                         return False;
830                 }
831
832                 /*
833                  * Non-encrypted passwords - convert to DOS codepage before encryption.
834                  */
835                 passlen = 24;
836                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
837         } else {
838                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
839                         if (!lp_client_plaintext_auth() && (*pass)) {
840                                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
841                                           " is disabled\n"));
842                                 return False;
843                         }
844
845                         /*
846                          * Non-encrypted passwords - convert to DOS codepage before using.
847                          */
848                         passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
849                         
850                 } else {
851                         memcpy(pword, pass, passlen);
852                 }
853         }
854
855         slprintf(fullshare, sizeof(fullshare)-1,
856                  "\\\\%s\\%s", cli->desthost, share);
857
858         set_message(cli->outbuf,4, 0, True);
859         SCVAL(cli->outbuf,smb_com,SMBtconX);
860         cli_setup_packet(cli);
861
862         SSVAL(cli->outbuf,smb_vwv0,0xFF);
863         SSVAL(cli->outbuf,smb_vwv3,passlen);
864
865         p = smb_buf(cli->outbuf);
866         memcpy(p,pword,passlen);
867         p += passlen;
868         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
869         fstrcpy(p, dev); p += strlen(dev)+1;
870
871         cli_setup_bcc(cli, p);
872
873         cli_send_smb(cli);
874         if (!cli_receive_smb(cli))
875                 return False;
876
877         if (cli_is_error(cli))
878                 return False;
879
880         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
881
882         if (cli->protocol >= PROTOCOL_NT1 &&
883             smb_buflen(cli->inbuf) == 3) {
884                 /* almost certainly win95 - enable bug fixes */
885                 cli->win95 = True;
886         }
887
888         cli->cnum = SVAL(cli->inbuf,smb_tid);
889         return True;
890 }
891
892 /****************************************************************************
893  Send a tree disconnect.
894 ****************************************************************************/
895
896 BOOL cli_tdis(struct cli_state *cli)
897 {
898         memset(cli->outbuf,'\0',smb_size);
899         set_message(cli->outbuf,0,0,True);
900         SCVAL(cli->outbuf,smb_com,SMBtdis);
901         SSVAL(cli->outbuf,smb_tid,cli->cnum);
902         cli_setup_packet(cli);
903         
904         cli_send_smb(cli);
905         if (!cli_receive_smb(cli))
906                 return False;
907         
908         return !cli_is_error(cli);
909 }
910
911 /****************************************************************************
912  Send a negprot command.
913 ****************************************************************************/
914
915 void cli_negprot_send(struct cli_state *cli)
916 {
917         char *p;
918         int numprots;
919
920         if (cli->protocol < PROTOCOL_NT1)
921                 cli->use_spnego = False;
922
923         memset(cli->outbuf,'\0',smb_size);
924
925         /* setup the protocol strings */
926         set_message(cli->outbuf,0,0,True);
927
928         p = smb_buf(cli->outbuf);
929         for (numprots=0;
930              prots[numprots].name && prots[numprots].prot<=cli->protocol;
931              numprots++) {
932                 *p++ = 2;
933                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
934         }
935
936         SCVAL(cli->outbuf,smb_com,SMBnegprot);
937         cli_setup_bcc(cli, p);
938         cli_setup_packet(cli);
939
940         SCVAL(smb_buf(cli->outbuf),0,2);
941
942         cli_send_smb(cli);
943 }
944
945 /****************************************************************************
946  Send a negprot command.
947 ****************************************************************************/
948
949 BOOL cli_negprot(struct cli_state *cli)
950 {
951         char *p;
952         int numprots;
953         int plength;
954
955         if (cli->protocol < PROTOCOL_NT1)
956                 cli->use_spnego = False;
957
958         memset(cli->outbuf,'\0',smb_size);
959
960         /* setup the protocol strings */
961         for (plength=0,numprots=0;
962              prots[numprots].name && prots[numprots].prot<=cli->protocol;
963              numprots++)
964                 plength += strlen(prots[numprots].name)+2;
965     
966         set_message(cli->outbuf,0,plength,True);
967
968         p = smb_buf(cli->outbuf);
969         for (numprots=0;
970              prots[numprots].name && prots[numprots].prot<=cli->protocol;
971              numprots++) {
972                 *p++ = 2;
973                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
974         }
975
976         SCVAL(cli->outbuf,smb_com,SMBnegprot);
977         cli_setup_packet(cli);
978
979         SCVAL(smb_buf(cli->outbuf),0,2);
980
981         cli_send_smb(cli);
982         if (!cli_receive_smb(cli))
983                 return False;
984
985         show_msg(cli->inbuf);
986
987         if (cli_is_error(cli) ||
988             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
989                 return(False);
990         }
991
992         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
993
994         if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
995                 DEBUG(1,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
996                 return False;
997         }
998
999         if (cli->protocol >= PROTOCOL_NT1) {    
1000                 /* NT protocol */
1001                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
1002                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
1003                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
1004                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
1005                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
1006                 cli->serverzone *= 60;
1007                 /* this time arrives in real GMT */
1008                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1009                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1010                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1011                 if (cli->capabilities & CAP_RAW_MODE) {
1012                         cli->readbraw_supported = True;
1013                         cli->writebraw_supported = True;      
1014                 }
1015                 /* work out if they sent us a workgroup */
1016                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1017                     smb_buflen(cli->inbuf) > 8) {
1018                         clistr_pull(cli, cli->server_domain, 
1019                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
1020                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
1021                 }
1022
1023                 /*
1024                  * As signing is slow we only turn it on if either the client or
1025                  * the server require it. JRA.
1026                  */
1027
1028                 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
1029                         /* Fail if server says signing is mandatory and we don't want to support it. */
1030                         if (!cli->sign_info.allow_smb_signing) {
1031                                 DEBUG(1,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1032                                 return False;
1033                         }
1034                         cli->sign_info.negotiated_smb_signing = True;
1035                         cli->sign_info.mandatory_signing = True;
1036                 } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
1037                         /* Fail if client says signing is mandatory and the server doesn't support it. */
1038                         if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
1039                                 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1040                                 return False;
1041                         }
1042                         cli->sign_info.negotiated_smb_signing = True;
1043                         cli->sign_info.mandatory_signing = True;
1044                 }
1045
1046         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1047                 cli->use_spnego = False;
1048                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
1049                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
1050                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
1051                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
1052                 cli->serverzone *= 60;
1053                 /* this time is converted to GMT by make_unix_date */
1054                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
1055                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
1056                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
1057                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1058         } else {
1059                 /* the old core protocol */
1060                 cli->use_spnego = False;
1061                 cli->sec_mode = 0;
1062                 cli->serverzone = TimeDiff(time(NULL));
1063         }
1064
1065         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1066
1067         /* a way to force ascii SMB */
1068         if (getenv("CLI_FORCE_ASCII"))
1069                 cli->capabilities &= ~CAP_UNICODE;
1070
1071         return True;
1072 }
1073
1074 /****************************************************************************
1075  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1076 ****************************************************************************/
1077
1078 BOOL cli_session_request(struct cli_state *cli,
1079                          struct nmb_name *calling, struct nmb_name *called)
1080 {
1081         char *p;
1082         int len = 4;
1083         extern pstring user_socket_options;
1084
1085         memcpy(&(cli->calling), calling, sizeof(*calling));
1086         memcpy(&(cli->called ), called , sizeof(*called ));
1087   
1088         /* put in the destination name */
1089         p = cli->outbuf+len;
1090         name_mangle(cli->called .name, p, cli->called .name_type);
1091         len += name_len(p);
1092
1093         /* and my name */
1094         p = cli->outbuf+len;
1095         name_mangle(cli->calling.name, p, cli->calling.name_type);
1096         len += name_len(p);
1097
1098         /* 445 doesn't have session request */
1099         if (cli->port == 445)
1100                 return True;
1101
1102         /* send a session request (RFC 1002) */
1103         /* setup the packet length
1104          * Remove four bytes from the length count, since the length
1105          * field in the NBT Session Service header counts the number
1106          * of bytes which follow.  The cli_send_smb() function knows
1107          * about this and accounts for those four bytes.
1108          * CRH.
1109          */
1110         len -= 4;
1111         _smb_setlen(cli->outbuf,len);
1112         SCVAL(cli->outbuf,0,0x81);
1113
1114         cli_send_smb(cli);
1115         DEBUG(5,("Sent session request\n"));
1116
1117         if (!cli_receive_smb(cli))
1118                 return False;
1119
1120         if (CVAL(cli->inbuf,0) == 0x84) {
1121                 /* C. Hoch  9/14/95 Start */
1122                 /* For information, here is the response structure.
1123                  * We do the byte-twiddling to for portability.
1124                 struct RetargetResponse{
1125                 unsigned char type;
1126                 unsigned char flags;
1127                 int16 length;
1128                 int32 ip_addr;
1129                 int16 port;
1130                 };
1131                 */
1132                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1133                 /* SESSION RETARGET */
1134                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1135
1136                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1137                 if (cli->fd == -1)
1138                         return False;
1139
1140                 DEBUG(3,("Retargeted\n"));
1141
1142                 set_socket_options(cli->fd,user_socket_options);
1143
1144                 /* Try again */
1145                 {
1146                         static int depth;
1147                         BOOL ret;
1148                         if (depth > 4) {
1149                                 DEBUG(0,("Retarget recursion - failing\n"));
1150                                 return False;
1151                         }
1152                         depth++;
1153                         ret = cli_session_request(cli, calling, called);
1154                         depth--;
1155                         return ret;
1156                 }
1157         } /* C. Hoch 9/14/95 End */
1158
1159         if (CVAL(cli->inbuf,0) != 0x82) {
1160                 /* This is the wrong place to put the error... JRA. */
1161                 cli->rap_error = CVAL(cli->inbuf,4);
1162                 return False;
1163         }
1164         return(True);
1165 }
1166
1167 /****************************************************************************
1168  Open the client sockets.
1169 ****************************************************************************/
1170
1171 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1172 {
1173         extern pstring user_socket_options;
1174         int name_type = 0x20;
1175         char *p;
1176
1177         /* reasonable default hostname */
1178         if (!host) host = "*SMBSERVER";
1179
1180         fstrcpy(cli->desthost, host);
1181
1182         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1183         if ((p = strchr(cli->desthost, '#'))) {
1184                 name_type = strtol(p+1, NULL, 16);              
1185                 *p = 0;
1186         }
1187         
1188         if (!ip || is_zero_ip(*ip)) {
1189                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1190                         return False;
1191                 }
1192                 if (ip) *ip = cli->dest_ip;
1193         } else {
1194                 cli->dest_ip = *ip;
1195         }
1196
1197         if (getenv("LIBSMB_PROG")) {
1198                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1199         } else {
1200                 /* try 445 first, then 139 */
1201                 int port = cli->port?cli->port:445;
1202                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1203                                           port, cli->timeout);
1204                 if (cli->fd == -1 && cli->port == 0) {
1205                         port = 139;
1206                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1207                                                   port, cli->timeout);
1208                 }
1209                 if (cli->fd != -1)
1210                         cli->port = port;
1211         }
1212         if (cli->fd == -1) {
1213                 DEBUG(1,("Error connecting to %s (%s)\n",
1214                          ip?inet_ntoa(*ip):host,strerror(errno)));
1215                 return False;
1216         }
1217
1218         set_socket_options(cli->fd,user_socket_options);
1219
1220         return True;
1221 }
1222
1223 /****************************************************************************
1224  Initialise client credentials for authenticated pipe access.
1225 ****************************************************************************/
1226
1227 void init_creds(struct ntuser_creds *creds, const char* username,
1228                        const char* domain, const char* password)
1229 {
1230         ZERO_STRUCTP(creds);
1231
1232         pwd_set_cleartext(&creds->pwd, password);
1233
1234         fstrcpy(creds->user_name, username);
1235         fstrcpy(creds->domain, domain);
1236
1237         if (!*username) {
1238                 creds->pwd.null_pwd = True;
1239         }
1240 }
1241
1242 /**
1243    establishes a connection to after the negprot. 
1244    @param output_cli A fully initialised cli structure, non-null only on success
1245    @param dest_host The netbios name of the remote host
1246    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1247    @param port (optional) The destination port (0 for default)
1248    @param retry BOOL. Did this connection fail with a retryable error ?
1249
1250 */
1251 NTSTATUS cli_start_connection(struct cli_state **output_cli, 
1252                               const char *my_name, 
1253                               const char *dest_host, 
1254                               struct in_addr *dest_ip, int port,
1255                               int signing_state, int flags,
1256                               BOOL *retry) 
1257 {
1258         NTSTATUS nt_status;
1259         struct nmb_name calling;
1260         struct nmb_name called;
1261         struct cli_state *cli;
1262         struct in_addr ip;
1263
1264         if (retry)
1265                 *retry = False;
1266
1267         if (!my_name) 
1268                 my_name = global_myname();
1269         
1270         if (!(cli = cli_initialise(NULL)))
1271                 return NT_STATUS_NO_MEMORY;
1272         
1273         make_nmb_name(&calling, my_name, 0x0);
1274         make_nmb_name(&called , dest_host, 0x20);
1275
1276         if (cli_set_port(cli, port) != port) {
1277                 cli_shutdown(cli);
1278                 return NT_STATUS_UNSUCCESSFUL;
1279         }
1280
1281         cli_set_timeout(cli, 10000); /* 10 seconds. */
1282
1283         if (dest_ip)
1284                 ip = *dest_ip;
1285         else
1286                 ZERO_STRUCT(ip);
1287
1288 again:
1289
1290         DEBUG(3,("Connecting to host=%s\n", dest_host));
1291         
1292         if (!cli_connect(cli, dest_host, &ip)) {
1293                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1294                          nmb_namestr(&called), inet_ntoa(ip)));
1295                 cli_shutdown(cli);
1296                 return NT_STATUS_UNSUCCESSFUL;
1297         }
1298
1299         if (retry)
1300                 *retry = True;
1301
1302         if (!cli_session_request(cli, &calling, &called)) {
1303                 char *p;
1304                 DEBUG(1,("session request to %s failed (%s)\n", 
1305                          called.name, cli_errstr(cli)));
1306                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1307                         *p = 0;
1308                         goto again;
1309                 }
1310                 if (strcmp(called.name, "*SMBSERVER")) {
1311                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1312                         goto again;
1313                 }
1314                 return NT_STATUS_UNSUCCESSFUL;
1315         }
1316
1317         cli_setup_signing_state(cli, signing_state);
1318
1319         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1320                 cli->use_spnego = False;
1321         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1322                 cli->use_kerberos = True;
1323
1324         if (!cli_negprot(cli)) {
1325                 DEBUG(1,("failed negprot\n"));
1326                 nt_status = NT_STATUS_UNSUCCESSFUL;
1327                 cli_shutdown(cli);
1328                 return nt_status;
1329         }
1330
1331         *output_cli = cli;
1332         return NT_STATUS_OK;
1333 }
1334
1335
1336 /**
1337    establishes a connection right up to doing tconX, password specified.
1338    @param output_cli A fully initialised cli structure, non-null only on success
1339    @param dest_host The netbios name of the remote host
1340    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1341    @param port (optional) The destination port (0 for default)
1342    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1343    @param service_type The 'type' of serivice. 
1344    @param user Username, unix string
1345    @param domain User's domain
1346    @param password User's password, unencrypted unix string.
1347    @param retry BOOL. Did this connection fail with a retryable error ?
1348 */
1349
1350 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1351                              const char *my_name, 
1352                              const char *dest_host, 
1353                              struct in_addr *dest_ip, int port,
1354                              const char *service, const char *service_type,
1355                              const char *user, const char *domain, 
1356                              const char *password, int flags,
1357                              int signing_state,
1358                              BOOL *retry) 
1359 {
1360         struct ntuser_creds creds;
1361         NTSTATUS nt_status;
1362         struct cli_state *cli = NULL;
1363
1364         nt_status = cli_start_connection(&cli, my_name, dest_host, 
1365                                          dest_ip, port, signing_state, flags, retry);
1366         
1367         if (!NT_STATUS_IS_OK(nt_status)) {
1368                 return nt_status;
1369         }
1370
1371         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1372                                password, strlen(password)+1, 
1373                                domain)) {
1374                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1375                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1376                 } else {
1377                         nt_status = cli_nt_error(cli);
1378                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1379                         cli_shutdown(cli);
1380                         if (NT_STATUS_IS_OK(nt_status)) 
1381                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1382                         return nt_status;
1383                 }
1384         } 
1385
1386         if (service) {
1387                 if (!cli_send_tconX(cli, service, service_type,
1388                                     password, strlen(password)+1)) {
1389                         nt_status = cli_nt_error(cli);
1390                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1391                         cli_shutdown(cli);
1392                         if (NT_STATUS_IS_OK(nt_status)) {
1393                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1394                         }
1395                         return nt_status;
1396                 }
1397         }
1398
1399         init_creds(&creds, user, domain, password);
1400         cli_init_creds(cli, &creds);
1401
1402         *output_cli = cli;
1403         return NT_STATUS_OK;
1404 }
1405
1406 /****************************************************************************
1407  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1408 ****************************************************************************/
1409
1410 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1411                                      struct in_addr *pdest_ip)
1412 {
1413         struct nmb_name calling, called;
1414
1415         make_nmb_name(&calling, srchost, 0x0);
1416
1417         /*
1418          * If the called name is an IP address
1419          * then use *SMBSERVER immediately.
1420          */
1421
1422         if(is_ipaddress(desthost))
1423                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1424         else
1425                 make_nmb_name(&called, desthost, 0x20);
1426
1427         if (!cli_session_request(cli, &calling, &called)) {
1428                 struct nmb_name smbservername;
1429
1430                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1431
1432                 /*
1433                  * If the name wasn't *SMBSERVER then
1434                  * try with *SMBSERVER if the first name fails.
1435                  */
1436
1437                 if (nmb_name_equal(&called, &smbservername)) {
1438
1439                         /*
1440                          * The name used was *SMBSERVER, don't bother with another name.
1441                          */
1442
1443                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1444 with error %s.\n", desthost, cli_errstr(cli) ));
1445                         return False;
1446                 }
1447
1448                 /*
1449                  * We need to close the connection here but can't call cli_shutdown as
1450                  * will free an allocated cli struct. cli_close_connection was invented
1451                  * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1452                  */
1453
1454                 cli_close_connection(cli);
1455
1456                 if (!cli_initialise(cli) ||
1457                                 !cli_connect(cli, desthost, pdest_ip) ||
1458                                 !cli_session_request(cli, &calling, &smbservername)) {
1459                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1460 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1461                         return False;
1462                 }
1463         }
1464
1465         return True;
1466 }
1467
1468
1469
1470
1471
1472 /****************************************************************************
1473  Send an old style tcon.
1474 ****************************************************************************/
1475 NTSTATUS cli_raw_tcon(struct cli_state *cli, 
1476                       const char *service, const char *pass, const char *dev,
1477                       uint16 *max_xmit, uint16 *tid)
1478 {
1479         char *p;
1480
1481         if (!lp_client_plaintext_auth() && (*pass)) {
1482                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1483                           " is disabled\n"));
1484                 return NT_STATUS_ACCESS_DENIED;
1485         }
1486
1487         memset(cli->outbuf,'\0',smb_size);
1488         memset(cli->inbuf,'\0',smb_size);
1489
1490         set_message(cli->outbuf, 0, 0, True);
1491         SCVAL(cli->outbuf,smb_com,SMBtcon);
1492         cli_setup_packet(cli);
1493
1494         p = smb_buf(cli->outbuf);
1495         *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
1496         *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
1497         *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
1498
1499         cli_setup_bcc(cli, p);
1500
1501         cli_send_smb(cli);
1502         if (!cli_receive_smb(cli)) {
1503                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1504         }
1505
1506         if (cli_is_error(cli)) {
1507                 return cli_nt_error(cli);
1508         }
1509
1510         *max_xmit = SVAL(cli->inbuf, smb_vwv0);
1511         *tid = SVAL(cli->inbuf, smb_vwv1);
1512
1513         return NT_STATUS_OK;
1514 }
1515
1516 /* Return a cli_state pointing at the IPC$ share for the given server */
1517
1518 struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
1519                                          struct user_auth_info *user_info)
1520 {
1521         struct cli_state *cli;
1522         pstring myname;
1523         NTSTATUS nt_status;
1524
1525         get_myname(myname);
1526         
1527         nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC", 
1528                                         user_info->username, lp_workgroup(), user_info->password, 
1529                                         CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, Undefined, NULL);
1530
1531         if (NT_STATUS_IS_OK(nt_status)) {
1532                 return cli;
1533         } else if (is_ipaddress(server)) {
1534             /* windows 9* needs a correct NMB name for connections */
1535             fstring remote_name;
1536
1537             if (name_status_find("*", 0, 0, *server_ip, remote_name)) {
1538                 cli = get_ipc_connect(remote_name, server_ip, user_info);
1539                 if (cli)
1540                     return cli;
1541             }
1542         }
1543         return NULL;
1544 }
1545
1546 /* Return the IP address and workgroup of a master browser on the 
1547    network. */
1548
1549 struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
1550 {
1551         struct ip_service *ip_list;
1552         struct cli_state *cli;
1553         int i, count;
1554         struct in_addr server_ip; 
1555
1556         /* Go looking for workgroups by broadcasting on the local network */ 
1557
1558         if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
1559                 return False;
1560         }
1561
1562         for (i = 0; i < count; i++) {
1563                 static fstring name;
1564
1565                 if (!name_status_find("*", 0, 0x1d, ip_list[i].ip, name))
1566                         continue;
1567
1568                 if (!find_master_ip(name, &server_ip))
1569                         continue;
1570
1571                 pstrcpy(workgroup, name);
1572
1573                 DEBUG(4, ("found master browser %s, %s\n", 
1574                           name, inet_ntoa(ip_list[i].ip)));
1575
1576                 cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
1577
1578                 if (!cli)
1579                     continue;
1580                 
1581                 return cli;
1582         }
1583
1584         return NULL;
1585 }