(only for HEAD at the moment).
[ira/wip.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-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, -1, 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
192         set_message(cli->outbuf,13,0,True);
193         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
194         cli_setup_packet(cli);
195                         
196         SCVAL(cli->outbuf,smb_vwv0,0xFF);
197         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
198         SSVAL(cli->outbuf,smb_vwv3,2);
199         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
200         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
201         SSVAL(cli->outbuf,smb_vwv8,0);
202         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
203         p = smb_buf(cli->outbuf);
204         p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
205         SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
206         p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
207         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
208         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
209         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
210         cli_setup_bcc(cli, p);
211
212         cli_send_smb(cli);
213         if (!cli_receive_smb(cli))
214               return False;
215         
216         show_msg(cli->inbuf);
217         
218         if (cli_is_error(cli))
219                 return False;
220
221         cli->vuid = SVAL(cli->inbuf,smb_uid);
222         p = smb_buf(cli->inbuf);
223         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
224         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
225         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
226         fstrcpy(cli->user_name, user);
227
228         return True;
229 }
230
231 static void set_signing_on_cli (struct cli_state *cli, uint8 user_session_key[16], DATA_BLOB response) 
232 {
233         uint8 zero_sig[8];
234         ZERO_STRUCT(zero_sig);
235
236         DEBUG(5, ("Server returned security sig:\n"));
237         dump_data(5, &cli->inbuf[smb_ss_field], 8);
238
239         if (cli->sign_info.use_smb_signing) {
240                 DEBUG(5, ("smb signing already active on connection\n"));
241         } else if (memcmp(&cli->inbuf[smb_ss_field], zero_sig, 8) != 0) {
242
243                 DEBUG(3, ("smb signing enabled!\n"));
244                 cli->sign_info.use_smb_signing = True;
245                 cli_calculate_mac_key(cli, user_session_key, response);
246         } else {
247                 DEBUG(5, ("smb signing NOT enabled!\n"));
248         }
249 }
250
251 static void set_temp_signing_on_cli(struct cli_state *cli) 
252 {
253         if (cli->sign_info.negotiated_smb_signing)
254                 cli->sign_info.temp_smb_signing = True;
255 }
256
257
258 /****************************************************************************
259    do a NT1 NTLM/LM encrypted session setup
260    @param cli client state to create do session setup on
261    @param user username
262    @param pass *either* cleartext password (passlen !=24) or LM response.
263    @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
264    @param workgroup The user's domain.
265 ****************************************************************************/
266
267 static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, 
268                                   const char *pass, size_t passlen,
269                                   const char *ntpass, size_t ntpasslen,
270                                   const char *workgroup)
271 {
272         uint32 capabilities = cli_session_setup_capabilities(cli);
273         DATA_BLOB lm_response = data_blob(NULL, 0);
274         DATA_BLOB nt_response = data_blob(NULL, 0);
275         uchar user_session_key[16];
276         char *p;
277         BOOL have_plaintext = False;
278
279         if (passlen != 24) {
280                 uchar nt_hash[16];
281                 E_md4hash(pass, nt_hash);
282
283                 if (lp_client_ntlmv2_auth()) {
284                         uchar ntlm_v2_hash[16];
285                         uchar ntlmv2_response[16];
286                         uchar lmv2_response[16];
287                         DATA_BLOB ntlmv2_client_data;
288                         DATA_BLOB lmv2_client_data;
289                         DATA_BLOB server_chal;
290
291                         /* We don't use the NT# directly.  Instead we use it mashed up with
292                            the username and domain.
293                            This prevents username swapping during the auth exchange
294                         */
295                         if (!ntv2_owf_gen(nt_hash, user, workgroup, ntlm_v2_hash)) {
296                                 return False;
297                         }
298
299                         server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8)); 
300
301                         /* NTLMv2 */
302
303                         /* We also get to specify some random data */
304                         ntlmv2_client_data = data_blob(NULL, 20);
305                         generate_random_buffer(ntlmv2_client_data.data, ntlmv2_client_data.length, False);
306                         memset(ntlmv2_client_data.data, 'A', ntlmv2_client_data.length);
307
308                         /* Given that data, and the challenge from the server, generate a response */
309                         SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, ntlmv2_client_data, ntlmv2_response);
310
311                         /* put it into nt_response, for the code below to put into the packet */
312                         nt_response = data_blob(NULL, ntlmv2_client_data.length + sizeof(ntlmv2_response));
313                         memcpy(nt_response.data, ntlmv2_response, sizeof(ntlmv2_response));
314                         /* after the first 16 bytes is the random data we generated above, so the server can verify us with it */
315                         memcpy(nt_response.data + sizeof(ntlmv2_response), ntlmv2_client_data.data, ntlmv2_client_data.length);
316                         data_blob_free(&ntlmv2_client_data);
317
318
319                         /* LMv2 */
320
321                         /* We also get to specify some random data, but only 8 bytes (24 byte total response) */
322                         lmv2_client_data = data_blob(NULL, 8);
323                         generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length, False);
324                         memset(lmv2_client_data.data, 'B', lmv2_client_data.length);
325
326                         /* Calculate response */
327                         SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, lmv2_client_data, lmv2_response);
328
329                         /* Calculate response */
330                         lm_response = data_blob(NULL, lmv2_client_data.length + sizeof(lmv2_response));
331                         memcpy(lm_response.data, lmv2_response, sizeof(lmv2_response));
332                         /* after the first 16 bytes is the 8 bytes of random data we made above */
333                         memcpy(lm_response.data + sizeof(lmv2_response), lmv2_client_data.data, lmv2_client_data.length);
334                         data_blob_free(&lmv2_client_data);
335
336                         data_blob_free(&server_chal);
337
338                         /* The NTLMv2 calculations also provide a session key, for signing etc later */
339                         SMBsesskeygen_ntv2(ntlm_v2_hash, ntlmv2_response, user_session_key);
340
341                 } else {
342                         /* non encrypted password supplied. Ignore ntpass. */
343                         if (lp_client_lanman_auth()) {
344                                 lm_response = data_blob(NULL, 24);
345                                 SMBencrypt(pass,cli->secblob.data,lm_response.data);
346                         }
347
348                         nt_response = data_blob(NULL, 24);
349                         SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
350                         SMBsesskeygen_ntv1(nt_hash, NULL, user_session_key);
351                 }
352
353                 have_plaintext = True;
354                 set_temp_signing_on_cli(cli);
355         } else {
356                 /* pre-encrypted password supplied.  Only used for 
357                    security=server, can't do
358                    signing becouse we don't have oringial key */
359
360                 lm_response = data_blob(pass, passlen);
361                 nt_response = data_blob(ntpass, ntpasslen);
362         }
363
364         /* send a session setup command */
365         memset(cli->outbuf,'\0',smb_size);
366
367         set_message(cli->outbuf,13,0,True);
368         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
369         cli_setup_packet(cli);
370                         
371         SCVAL(cli->outbuf,smb_vwv0,0xFF);
372         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
373         SSVAL(cli->outbuf,smb_vwv3,2);
374         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
375         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
376         SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
377         SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
378         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
379         p = smb_buf(cli->outbuf);
380         if (lm_response.length) {
381                 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
382         }
383         if (nt_response.length) {
384                 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
385         }
386         p += clistr_push(cli, p, user, -1, STR_TERMINATE);
387         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE);
388         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
389         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
390         cli_setup_bcc(cli, p);
391
392         if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
393                 data_blob_free(&lm_response);
394                 data_blob_free(&nt_response);
395                 return False;
396         }
397
398         show_msg(cli->inbuf);
399
400         if (cli_is_error(cli)) {
401                 data_blob_free(&lm_response);
402                 data_blob_free(&nt_response);
403                 return False;
404         }
405
406         /* use the returned vuid from now on */
407         cli->vuid = SVAL(cli->inbuf,smb_uid);
408         
409         p = smb_buf(cli->inbuf);
410         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
411         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
412         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
413
414         fstrcpy(cli->user_name, user);
415
416         if (have_plaintext) {
417                 /* Have plaintext orginal */
418                 set_signing_on_cli(cli, user_session_key, nt_response);
419         }
420         
421         data_blob_free(&lm_response);
422         data_blob_free(&nt_response);
423         return True;
424 }
425
426 /****************************************************************************
427  Send a extended security session setup blob, returning a reply blob.
428 ****************************************************************************/
429
430 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
431 {
432         uint32 capabilities = cli_session_setup_capabilities(cli);
433         char *p;
434         DATA_BLOB blob2;
435         uint32 len;
436
437         blob2 = data_blob(NULL, 0);
438
439         capabilities |= CAP_EXTENDED_SECURITY;
440
441         /* send a session setup command */
442         memset(cli->outbuf,'\0',smb_size);
443
444         set_message(cli->outbuf,12,0,True);
445         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
446
447         set_temp_signing_on_cli(cli);
448
449         cli_setup_packet(cli);
450                         
451         SCVAL(cli->outbuf,smb_vwv0,0xFF);
452         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
453         SSVAL(cli->outbuf,smb_vwv3,2);
454         SSVAL(cli->outbuf,smb_vwv4,1);
455         SIVAL(cli->outbuf,smb_vwv5,0);
456         SSVAL(cli->outbuf,smb_vwv7,blob.length);
457         SIVAL(cli->outbuf,smb_vwv10,capabilities); 
458         p = smb_buf(cli->outbuf);
459         memcpy(p, blob.data, blob.length);
460         p += blob.length;
461         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
462         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
463         cli_setup_bcc(cli, p);
464         cli_send_smb(cli);
465
466         if (!cli_receive_smb(cli))
467                 return blob2;
468
469         show_msg(cli->inbuf);
470
471         if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
472                                                   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
473                 return blob2;
474         }
475         
476         /* use the returned vuid from now on */
477         cli->vuid = SVAL(cli->inbuf,smb_uid);
478         
479         p = smb_buf(cli->inbuf);
480
481         blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
482
483         p += blob2.length;
484         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
485
486         /* w2k with kerberos doesn't properly null terminate this field */
487         len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
488         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
489
490         return blob2;
491 }
492
493 #ifdef HAVE_KRB5
494 /****************************************************************************
495  Do a spnego/kerberos encrypted session setup.
496 ****************************************************************************/
497
498 static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
499 {
500         DATA_BLOB blob2, negTokenTarg;
501
502         DEBUG(2,("Doing kerberos session setup\n"));
503
504         /* generate the encapsulated kerberos5 ticket */
505         negTokenTarg = spnego_gen_negTokenTarg(principal, 0);
506
507         if (!negTokenTarg.data) return False;
508
509 #if 0
510         file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
511 #endif
512
513         blob2 = cli_session_setup_blob(cli, negTokenTarg);
514
515         /* we don't need this blob for kerberos */
516         data_blob_free(&blob2);
517
518         data_blob_free(&negTokenTarg);
519
520         return !cli_is_error(cli);
521 }
522 #endif
523
524 /****************************************************************************
525  Do a spnego/NTLMSSP encrypted session setup.
526 ****************************************************************************/
527
528 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, 
529                                       const char *pass, const char *workgroup)
530 {
531         DATA_BLOB msg1, struct_blob;
532         DATA_BLOB blob, chal1, chal2, auth, challenge_blob;
533         uint8 challenge[8];
534         uint8 nthash[24], lmhash[24], sess_key[16];
535         uint32 neg_flags, chal_flags, ntlmssp_command, unkn1, unkn2;
536         pstring server_domain;  /* FIX THIS, SHOULD be UCS2-LE */
537
538         neg_flags = NTLMSSP_NEGOTIATE_UNICODE | 
539                 NTLMSSP_NEGOTIATE_128 | 
540                 NTLMSSP_NEGOTIATE_NTLM |
541                 NTLMSSP_REQUEST_TARGET;
542
543         memset(sess_key, 0, 16);
544
545         DEBUG(10, ("sending NTLMSSP_NEGOTIATE\n"));
546
547         /* generate the ntlmssp negotiate packet */
548         msrpc_gen(&blob, "CddAA",
549                   "NTLMSSP",
550                   NTLMSSP_NEGOTIATE,
551                   neg_flags,
552                   workgroup, 
553                   cli->calling.name);
554         DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n",
555                   neg_flags, workgroup, cli->calling.name));
556         /* and wrap it in a SPNEGO wrapper */
557         msg1 = gen_negTokenInit(OID_NTLMSSP, blob);
558         data_blob_free(&blob);
559
560         /* now send that blob on its way */
561         blob = cli_session_setup_blob(cli, msg1);
562
563         data_blob_free(&msg1);
564
565         if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED))
566                 return False;
567
568 #if 0
569         file_save("chal.dat", blob.data, blob.length);
570 #endif
571
572         /* the server gives us back two challenges */
573         if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
574                 DEBUG(3,("Failed to parse challenges\n"));
575                 return False;
576         }
577
578         data_blob_free(&blob);
579
580         /*
581          * Ok, chal1 and chal2 are actually two identical copies of
582          * the NTLMSSP Challenge BLOB, and they contain, encoded in them
583          * the challenge to use.
584          */
585
586         if (!msrpc_parse(&chal1, "CdUdbddB",
587                          "NTLMSSP",
588                          &ntlmssp_command, 
589                          &server_domain,
590                          &chal_flags,
591                          &challenge_blob, 8,
592                          &unkn1, &unkn2,
593                          &struct_blob)) {
594           DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
595           return False;
596         }
597                         
598         if (ntlmssp_command != NTLMSSP_CHALLENGE) {
599                 DEBUG(0, ("NTLMSSP Response != NTLMSSP_CHALLENGE. Got %0X\n", 
600                         ntlmssp_command));
601                 return False;
602         }
603  
604         if (challenge_blob.length < 8) {
605                 return False;
606         }
607
608         DEBUG(10, ("Challenge:\n"));
609         dump_data(10, challenge_blob.data, 8);
610
611         /* encrypt the password with the challenge which is in the blob */
612         memcpy(challenge, challenge_blob.data, 8); 
613         SMBencrypt(pass, challenge,lmhash);
614         SMBNTencrypt(pass, challenge,nthash);
615         data_blob_free(&challenge_blob);
616
617 #if 0
618         file_save("nthash.dat", nthash, 24);
619         file_save("lmhash.dat", lmhash, 24);
620         file_save("chal1.dat", chal1.data, chal1.length);
621 #endif
622
623         data_blob_free(&chal1);
624         data_blob_free(&chal2);
625
626         /* this generates the actual auth packet */
627         msrpc_gen(&blob, "CdBBUUUBd", 
628                   "NTLMSSP", 
629                   NTLMSSP_AUTH, 
630                   lmhash, 24,
631                   nthash, 24,
632                   workgroup, 
633                   user, 
634                   cli->calling.name,
635                   sess_key, 0,
636                   neg_flags);
637
638         /* wrap it in SPNEGO */
639         auth = spnego_gen_auth(blob);
640
641         data_blob_free(&blob);
642
643         /* now send the auth packet and we should be done */
644         blob = cli_session_setup_blob(cli, auth);
645
646         data_blob_free(&auth);
647         data_blob_free(&blob);
648
649         if (cli_is_error(cli))
650                 return False;
651
652         return True;
653 }
654
655 /****************************************************************************
656  Do a spnego encrypted session setup.
657 ****************************************************************************/
658
659 static BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user, 
660                                      const char *pass, const char *workgroup)
661 {
662         char *principal;
663         char *OIDs[ASN1_MAX_OIDS];
664         int i;
665         BOOL got_kerberos_mechanism = False;
666         DATA_BLOB blob;
667
668         DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
669
670         /* the server might not even do spnego */
671         if (cli->secblob.length <= 16) {
672                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
673                 goto ntlmssp;
674         }
675
676 #if 0
677         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
678 #endif
679
680         /* there is 16 bytes of GUID before the real spnego packet starts */
681         blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
682
683         /* the server sent us the first part of the SPNEGO exchange in the negprot 
684            reply */
685         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
686                 data_blob_free(&blob);
687                 return False;
688         }
689         data_blob_free(&blob);
690
691         /* make sure the server understands kerberos */
692         for (i=0;OIDs[i];i++) {
693                 DEBUG(3,("got OID=%s\n", OIDs[i]));
694                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
695                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
696                         got_kerberos_mechanism = True;
697                 }
698                 free(OIDs[i]);
699         }
700         DEBUG(3,("got principal=%s\n", principal));
701
702         fstrcpy(cli->user_name, user);
703
704 #ifdef HAVE_KRB5
705         if (got_kerberos_mechanism && cli->use_kerberos) {
706                 return cli_session_setup_kerberos(cli, principal, workgroup);
707         }
708 #endif
709
710         free(principal);
711
712 ntlmssp:
713
714         return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
715 }
716
717 /****************************************************************************
718  Send a session setup. The username and workgroup is in UNIX character
719  format and must be converted to DOS codepage format before sending. If the
720  password is in plaintext, the same should be done.
721 ****************************************************************************/
722
723 BOOL cli_session_setup(struct cli_state *cli, 
724                        const char *user, 
725                        const char *pass, int passlen,
726                        const char *ntpass, int ntpasslen,
727                        const char *workgroup)
728 {
729         char *p;
730         fstring user2;
731
732         /* allow for workgroups as part of the username */
733         fstrcpy(user2, user);
734         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
735             (p=strchr_m(user2,*lp_winbind_separator()))) {
736                 *p = 0;
737                 user = p+1;
738                 workgroup = user2;
739         }
740
741         if (cli->protocol < PROTOCOL_LANMAN1)
742                 return True;
743
744         /* now work out what sort of session setup we are going to
745            do. I have split this into separate functions to make the
746            flow a bit easier to understand (tridge) */
747
748         /* if its an older server then we have to use the older request format */
749
750         if (cli->protocol < PROTOCOL_NT1)
751                 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
752
753         /* if no user is supplied then we have to do an anonymous connection.
754            passwords are ignored */
755
756         if (!user || !*user)
757                 return cli_session_setup_guest(cli);
758
759         /* if the server is share level then send a plaintext null
760            password at this point. The password is sent in the tree
761            connect */
762
763         if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
764                 return cli_session_setup_plaintext(cli, user, "", workgroup);
765
766         /* if the server doesn't support encryption then we have to use 
767            plaintext. The second password is ignored */
768
769         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0)
770                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
771
772         /* Indidicate signing */
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
810 BOOL cli_send_tconX(struct cli_state *cli, 
811                     const char *share, const char *dev, const char *pass, int passlen)
812 {
813         fstring fullshare, pword;
814         char *p;
815         memset(cli->outbuf,'\0',smb_size);
816         memset(cli->inbuf,'\0',smb_size);
817
818         fstrcpy(cli->share, share);
819
820         /* in user level security don't send a password now */
821         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
822                 passlen = 1;
823                 pass = "";
824         }
825
826         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
827                 /*
828                  * Non-encrypted passwords - convert to DOS codepage before encryption.
829                  */
830                 passlen = 24;
831                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
832         } else {
833                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
834                         /*
835                          * Non-encrypted passwords - convert to DOS codepage before using.
836                          */
837                         passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
838                 } else {
839                         memcpy(pword, pass, passlen);
840                 }
841         }
842
843         if (cli->port == 445) {
844                 slprintf(fullshare, sizeof(fullshare)-1,
845                          "%s", share);
846         } else {
847                 slprintf(fullshare, sizeof(fullshare)-1,
848                          "\\\\%s\\%s", cli->desthost, share);
849         }
850
851         set_message(cli->outbuf,4, 0, True);
852         SCVAL(cli->outbuf,smb_com,SMBtconX);
853         cli_setup_packet(cli);
854
855         SSVAL(cli->outbuf,smb_vwv0,0xFF);
856         SSVAL(cli->outbuf,smb_vwv3,passlen);
857
858         p = smb_buf(cli->outbuf);
859         memcpy(p,pword,passlen);
860         p += passlen;
861         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
862         fstrcpy(p, dev); p += strlen(dev)+1;
863
864         cli_setup_bcc(cli, p);
865
866         cli_send_smb(cli);
867         if (!cli_receive_smb(cli))
868                 return False;
869
870         if (cli_is_error(cli))
871                 return False;
872
873         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
874
875         if (strcasecmp(share,"IPC$")==0)
876                 fstrcpy(cli->dev, "IPC");
877
878         if (cli->protocol >= PROTOCOL_NT1 &&
879             smb_buflen(cli->inbuf) == 3) {
880                 /* almost certainly win95 - enable bug fixes */
881                 cli->win95 = True;
882         }
883
884         cli->cnum = SVAL(cli->inbuf,smb_tid);
885         return True;
886 }
887
888 /****************************************************************************
889  Send a tree disconnect.
890 ****************************************************************************/
891
892 BOOL cli_tdis(struct cli_state *cli)
893 {
894         memset(cli->outbuf,'\0',smb_size);
895         set_message(cli->outbuf,0,0,True);
896         SCVAL(cli->outbuf,smb_com,SMBtdis);
897         SSVAL(cli->outbuf,smb_tid,cli->cnum);
898         cli_setup_packet(cli);
899         
900         cli_send_smb(cli);
901         if (!cli_receive_smb(cli))
902                 return False;
903         
904         return !cli_is_error(cli);
905 }
906
907 /****************************************************************************
908  Send a negprot command.
909 ****************************************************************************/
910
911 void cli_negprot_send(struct cli_state *cli)
912 {
913         char *p;
914         int numprots;
915
916         if (cli->protocol < PROTOCOL_NT1)
917                 cli->use_spnego = False;
918
919         memset(cli->outbuf,'\0',smb_size);
920
921         /* setup the protocol strings */
922         set_message(cli->outbuf,0,0,True);
923
924         p = smb_buf(cli->outbuf);
925         for (numprots=0;
926              prots[numprots].name && prots[numprots].prot<=cli->protocol;
927              numprots++) {
928                 *p++ = 2;
929                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
930         }
931
932         SCVAL(cli->outbuf,smb_com,SMBnegprot);
933         cli_setup_bcc(cli, p);
934         cli_setup_packet(cli);
935
936         SCVAL(smb_buf(cli->outbuf),0,2);
937
938         cli_send_smb(cli);
939 }
940
941 /****************************************************************************
942  Send a negprot command.
943 ****************************************************************************/
944
945 BOOL cli_negprot(struct cli_state *cli)
946 {
947         char *p;
948         int numprots;
949         int plength;
950
951         if (cli->sign_info.use_smb_signing) {
952                 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
953                 return False;
954         }
955
956         if (cli->protocol < PROTOCOL_NT1)
957                 cli->use_spnego = False;
958
959         memset(cli->outbuf,'\0',smb_size);
960
961         /* setup the protocol strings */
962         for (plength=0,numprots=0;
963              prots[numprots].name && prots[numprots].prot<=cli->protocol;
964              numprots++)
965                 plength += strlen(prots[numprots].name)+2;
966     
967         set_message(cli->outbuf,0,plength,True);
968
969         p = smb_buf(cli->outbuf);
970         for (numprots=0;
971              prots[numprots].name && prots[numprots].prot<=cli->protocol;
972              numprots++) {
973                 *p++ = 2;
974                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
975         }
976
977         SCVAL(cli->outbuf,smb_com,SMBnegprot);
978         cli_setup_packet(cli);
979
980         SCVAL(smb_buf(cli->outbuf),0,2);
981
982         cli_send_smb(cli);
983         if (!cli_receive_smb(cli))
984                 return False;
985
986         show_msg(cli->inbuf);
987
988         if (cli_is_error(cli) ||
989             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
990                 return(False);
991         }
992
993         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
994
995         if (cli->protocol >= PROTOCOL_NT1) {    
996                 /* NT protocol */
997                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
998                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
999                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
1000                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
1001                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
1002                 cli->serverzone *= 60;
1003                 /* this time arrives in real GMT */
1004                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1005                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1006                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1007                 if (cli->capabilities & CAP_RAW_MODE) {
1008                         cli->readbraw_supported = True;
1009                         cli->writebraw_supported = True;      
1010                 }
1011                 /* work out if they sent us a workgroup */
1012                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1013                     smb_buflen(cli->inbuf) > 8) {
1014                         clistr_pull(cli, cli->server_domain, 
1015                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
1016                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
1017                 }
1018
1019                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED))
1020                         cli->sign_info.negotiated_smb_signing = True;
1021
1022                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && cli->sign_info.allow_smb_signing)
1023                         cli->sign_info.negotiated_smb_signing = True;
1024
1025         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1026                 cli->use_spnego = False;
1027                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
1028                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
1029                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
1030                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
1031                 cli->serverzone *= 60;
1032                 /* this time is converted to GMT by make_unix_date */
1033                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
1034                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
1035                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
1036                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1037         } else {
1038                 /* the old core protocol */
1039                 cli->use_spnego = False;
1040                 cli->sec_mode = 0;
1041                 cli->serverzone = TimeDiff(time(NULL));
1042         }
1043
1044         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1045
1046         /* a way to force ascii SMB */
1047         if (getenv("CLI_FORCE_ASCII"))
1048                 cli->capabilities &= ~CAP_UNICODE;
1049
1050         return True;
1051 }
1052
1053 /****************************************************************************
1054  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1055 ****************************************************************************/
1056
1057 BOOL cli_session_request(struct cli_state *cli,
1058                          struct nmb_name *calling, struct nmb_name *called)
1059 {
1060         char *p;
1061         int len = 4;
1062         extern pstring user_socket_options;
1063
1064         memcpy(&(cli->calling), calling, sizeof(*calling));
1065         memcpy(&(cli->called ), called , sizeof(*called ));
1066   
1067         /* put in the destination name */
1068         p = cli->outbuf+len;
1069         name_mangle(cli->called .name, p, cli->called .name_type);
1070         len += name_len(p);
1071
1072         /* and my name */
1073         p = cli->outbuf+len;
1074         name_mangle(cli->calling.name, p, cli->calling.name_type);
1075         len += name_len(p);
1076
1077         /* 445 doesn't have session request */
1078         if (cli->port == 445)
1079                 return True;
1080
1081         if (cli->sign_info.use_smb_signing) {
1082                 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
1083                 return False;
1084         }
1085
1086         /* send a session request (RFC 1002) */
1087         /* setup the packet length
1088          * Remove four bytes from the length count, since the length
1089          * field in the NBT Session Service header counts the number
1090          * of bytes which follow.  The cli_send_smb() function knows
1091          * about this and accounts for those four bytes.
1092          * CRH.
1093          */
1094         len -= 4;
1095         _smb_setlen(cli->outbuf,len);
1096         SCVAL(cli->outbuf,0,0x81);
1097
1098         cli_send_smb(cli);
1099         DEBUG(5,("Sent session request\n"));
1100
1101         if (!cli_receive_smb(cli))
1102                 return False;
1103
1104         if (CVAL(cli->inbuf,0) == 0x84) {
1105                 /* C. Hoch  9/14/95 Start */
1106                 /* For information, here is the response structure.
1107                  * We do the byte-twiddling to for portability.
1108                 struct RetargetResponse{
1109                 unsigned char type;
1110                 unsigned char flags;
1111                 int16 length;
1112                 int32 ip_addr;
1113                 int16 port;
1114                 };
1115                 */
1116                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1117                 /* SESSION RETARGET */
1118                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1119
1120                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1121                 if (cli->fd == -1)
1122                         return False;
1123
1124                 DEBUG(3,("Retargeted\n"));
1125
1126                 set_socket_options(cli->fd,user_socket_options);
1127
1128                 /* Try again */
1129                 {
1130                         static int depth;
1131                         BOOL ret;
1132                         if (depth > 4) {
1133                                 DEBUG(0,("Retarget recursion - failing\n"));
1134                                 return False;
1135                         }
1136                         depth++;
1137                         ret = cli_session_request(cli, calling, called);
1138                         depth--;
1139                         return ret;
1140                 }
1141         } /* C. Hoch 9/14/95 End */
1142
1143         if (CVAL(cli->inbuf,0) != 0x82) {
1144                 /* This is the wrong place to put the error... JRA. */
1145                 cli->rap_error = CVAL(cli->inbuf,4);
1146                 return False;
1147         }
1148         return(True);
1149 }
1150
1151 /****************************************************************************
1152  Open the client sockets.
1153 ****************************************************************************/
1154
1155 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1156 {
1157         extern pstring user_socket_options;
1158         int name_type = 0x20;
1159         char *p;
1160
1161         /* reasonable default hostname */
1162         if (!host) host = "*SMBSERVER";
1163
1164         fstrcpy(cli->desthost, host);
1165
1166         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1167         if ((p = strchr(cli->desthost, '#'))) {
1168                 name_type = strtol(p+1, NULL, 16);              
1169                 *p = 0;
1170         }
1171         
1172         if (!ip || is_zero_ip(*ip)) {
1173                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1174                         return False;
1175                 }
1176                 if (ip) *ip = cli->dest_ip;
1177         } else {
1178                 cli->dest_ip = *ip;
1179         }
1180
1181         if (getenv("LIBSMB_PROG")) {
1182                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1183         } else {
1184                 /* try 445 first, then 139 */
1185                 int port = cli->port?cli->port:445;
1186                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1187                                           port, cli->timeout);
1188                 if (cli->fd == -1 && cli->port == 0) {
1189                         port = 139;
1190                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1191                                                   port, cli->timeout);
1192                 }
1193                 if (cli->fd != -1)
1194                         cli->port = port;
1195         }
1196         if (cli->fd == -1) {
1197                 DEBUG(1,("Error connecting to %s (%s)\n",
1198                          ip?inet_ntoa(*ip):host,strerror(errno)));
1199                 return False;
1200         }
1201
1202         set_socket_options(cli->fd,user_socket_options);
1203
1204         return True;
1205 }
1206
1207 /****************************************************************************
1208  Initialise client credentials for authenticated pipe access.
1209 ****************************************************************************/
1210
1211 static void init_creds(struct ntuser_creds *creds, const char* username,
1212                        const char* domain, const char* password)
1213 {
1214         ZERO_STRUCTP(creds);
1215
1216         pwd_set_cleartext(&creds->pwd, password);
1217
1218         fstrcpy(creds->user_name, username);
1219         fstrcpy(creds->domain, domain);
1220
1221         if (!*username) {
1222                 creds->pwd.null_pwd = True;
1223         }
1224 }
1225
1226 /**
1227    establishes a connection right up to doing tconX, password specified.
1228    @param output_cli A fully initialised cli structure, non-null only on success
1229    @param dest_host The netbios name of the remote host
1230    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1231    @param port (optional) The destination port (0 for default)
1232    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1233    @param service_type The 'type' of serivice. 
1234    @param user Username, unix string
1235    @param domain User's domain
1236    @param password User's password, unencrypted unix string.
1237    @param retry BOOL. Did this connection fail with a retryable error ?
1238 */
1239
1240 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1241                              const char *my_name, 
1242                              const char *dest_host, 
1243                              struct in_addr *dest_ip, int port,
1244                              const char *service, const char *service_type,
1245                              const char *user, const char *domain, 
1246                              const char *password, int flags,
1247                              BOOL *retry) 
1248 {
1249         struct ntuser_creds creds;
1250         NTSTATUS nt_status;
1251         struct nmb_name calling;
1252         struct nmb_name called;
1253         struct cli_state *cli;
1254         struct in_addr ip;
1255
1256         if (retry)
1257                 *retry = False;
1258
1259         if (!my_name) 
1260                 my_name = global_myname();
1261         
1262         if (!(cli = cli_initialise(NULL)))
1263                 return NT_STATUS_NO_MEMORY;
1264         
1265         make_nmb_name(&calling, my_name, 0x0);
1266         make_nmb_name(&called , dest_host, 0x20);
1267
1268         if (cli_set_port(cli, port) != port) {
1269                 cli_shutdown(cli);
1270                 return NT_STATUS_UNSUCCESSFUL;
1271         }
1272
1273         cli_set_timeout(cli, 10000); /* 10 seconds. */
1274
1275         if (dest_ip)
1276                 ip = *dest_ip;
1277         else
1278                 ZERO_STRUCT(ip);
1279
1280 again:
1281
1282         DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1283         
1284         if (!cli_connect(cli, dest_host, &ip)) {
1285                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1286                          nmb_namestr(&called), inet_ntoa(ip)));
1287                 cli_shutdown(cli);
1288                 return NT_STATUS_UNSUCCESSFUL;
1289         }
1290
1291         if (retry)
1292                 *retry = True;
1293
1294         if (!cli_session_request(cli, &calling, &called)) {
1295                 char *p;
1296                 DEBUG(1,("session request to %s failed (%s)\n", 
1297                          called.name, cli_errstr(cli)));
1298                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1299                         *p = 0;
1300                         goto again;
1301                 }
1302                 if (strcmp(called.name, "*SMBSERVER")) {
1303                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1304                         goto again;
1305                 }
1306                 return NT_STATUS_UNSUCCESSFUL;
1307         }
1308
1309         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1310                 cli->use_spnego = False;
1311         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1312                 cli->use_kerberos = True;
1313
1314         if (!cli_negprot(cli)) {
1315                 DEBUG(1,("failed negprot\n"));
1316                 nt_status = NT_STATUS_UNSUCCESSFUL;
1317                 cli_shutdown(cli);
1318                 return nt_status;
1319         }
1320
1321         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1322                                password, strlen(password)+1, 
1323                                domain)) {
1324                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1325                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1326                 } else {
1327                         nt_status = cli_nt_error(cli);
1328                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1329                         cli_shutdown(cli);
1330                         if (NT_STATUS_IS_OK(nt_status)) 
1331                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1332                         return nt_status;
1333                 }
1334         } 
1335
1336         if (service) {
1337                 if (!cli_send_tconX(cli, service, service_type,
1338                                     password, strlen(password)+1)) {
1339                         nt_status = cli_nt_error(cli);
1340                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1341                         cli_shutdown(cli);
1342                         if (NT_STATUS_IS_OK(nt_status)) {
1343                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1344                         }
1345                         return nt_status;
1346                 }
1347         }
1348
1349         init_creds(&creds, user, domain, password);
1350         cli_init_creds(cli, &creds);
1351
1352         *output_cli = cli;
1353         return NT_STATUS_OK;
1354 }
1355
1356 /****************************************************************************
1357  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1358 ****************************************************************************/
1359
1360 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1361                                      struct in_addr *pdest_ip)
1362 {
1363         struct nmb_name calling, called;
1364
1365         make_nmb_name(&calling, srchost, 0x0);
1366
1367         /*
1368          * If the called name is an IP address
1369          * then use *SMBSERVER immediately.
1370          */
1371
1372         if(is_ipaddress(desthost))
1373                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1374         else
1375                 make_nmb_name(&called, desthost, 0x20);
1376
1377         if (!cli_session_request(cli, &calling, &called)) {
1378                 struct nmb_name smbservername;
1379
1380                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1381
1382                 /*
1383                  * If the name wasn't *SMBSERVER then
1384                  * try with *SMBSERVER if the first name fails.
1385                  */
1386
1387                 if (nmb_name_equal(&called, &smbservername)) {
1388
1389                         /*
1390                          * The name used was *SMBSERVER, don't bother with another name.
1391                          */
1392
1393                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1394 with error %s.\n", desthost, cli_errstr(cli) ));
1395                         return False;
1396                 }
1397
1398                 /*
1399                  * We need to close the connection here but can't call cli_shutdown as
1400                  * will free an allocated cli struct. cli_close_connection was invented
1401                  * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1402                  */
1403
1404                 cli_close_connection(cli);
1405
1406                 if (!cli_initialise(cli) ||
1407                                 !cli_connect(cli, desthost, pdest_ip) ||
1408                                 !cli_session_request(cli, &calling, &smbservername)) {
1409                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1410 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1411                         return False;
1412                 }
1413         }
1414
1415         return True;
1416 }