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