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