Commit to HEAD the updates to smb signing code that I was propsing for 3.0.
[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         /* 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); 
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); 
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                 if (cli_simple_set_signing(cli, key, null_blob)) {
647                         
648                         /* 'resign' the last message, so we get the right sequence numbers
649                            for checking the first reply from the server */
650                         cli_calculate_sign_mac(cli);
651                         
652                         if (!cli_check_sign_mac(cli, True)) {
653                                 nt_status = NT_STATUS_ACCESS_DENIED;
654                         }
655                 }
656         }
657
658         /* we have a reference conter on ntlmssp_state, if we are signing
659            then the state will be kept by the signing engine */
660
661         ntlmssp_end(&ntlmssp_state);
662
663         return nt_status;
664 }
665
666 /****************************************************************************
667  Do a spnego encrypted session setup.
668 ****************************************************************************/
669
670 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, 
671                               const char *pass, const char *domain)
672 {
673         char *principal;
674         char *OIDs[ASN1_MAX_OIDS];
675         int i;
676         BOOL got_kerberos_mechanism = False;
677         DATA_BLOB blob;
678
679         DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
680
681         /* the server might not even do spnego */
682         if (cli->secblob.length <= 16) {
683                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
684                 goto ntlmssp;
685         }
686
687 #if 0
688         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
689 #endif
690
691         /* there is 16 bytes of GUID before the real spnego packet starts */
692         blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
693
694         /* the server sent us the first part of the SPNEGO exchange in the negprot 
695            reply */
696         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
697                 data_blob_free(&blob);
698                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
699         }
700         data_blob_free(&blob);
701
702         /* make sure the server understands kerberos */
703         for (i=0;OIDs[i];i++) {
704                 DEBUG(3,("got OID=%s\n", OIDs[i]));
705                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
706                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
707                         got_kerberos_mechanism = True;
708                 }
709                 free(OIDs[i]);
710         }
711         DEBUG(3,("got principal=%s\n", principal));
712
713         fstrcpy(cli->user_name, user);
714
715 #ifdef HAVE_KRB5
716         /* If password is set we reauthenticate to kerberos server
717          * and do not store results */
718
719         if (got_kerberos_mechanism && cli->use_kerberos) {
720                 if (pass && *pass) {
721                         int ret;
722                         
723                         use_in_memory_ccache();
724                         ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */);
725                         
726                         if (ret){
727                                 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
728                                 return ADS_ERROR_KRB5(ret);
729                         }
730                 }
731                 
732                 return cli_session_setup_kerberos(cli, principal, domain);
733         }
734 #endif
735
736         free(principal);
737
738 ntlmssp:
739
740         return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, user, pass, domain));
741 }
742
743 /****************************************************************************
744  Send a session setup. The username and workgroup is in UNIX character
745  format and must be converted to DOS codepage format before sending. If the
746  password is in plaintext, the same should be done.
747 ****************************************************************************/
748
749 BOOL cli_session_setup(struct cli_state *cli, 
750                        const char *user, 
751                        const char *pass, int passlen,
752                        const char *ntpass, int ntpasslen,
753                        const char *workgroup)
754 {
755         char *p;
756         fstring user2;
757
758         /* allow for workgroups as part of the username */
759         fstrcpy(user2, user);
760         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
761             (p=strchr_m(user2,*lp_winbind_separator()))) {
762                 *p = 0;
763                 user = p+1;
764                 workgroup = user2;
765         }
766
767         if (cli->protocol < PROTOCOL_LANMAN1)
768                 return True;
769
770         /* now work out what sort of session setup we are going to
771            do. I have split this into separate functions to make the
772            flow a bit easier to understand (tridge) */
773
774         /* if its an older server then we have to use the older request format */
775
776         if (cli->protocol < PROTOCOL_NT1) {
777                 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
778                         DEBUG(1, ("Server requested LM password but 'client lanman auth'"
779                                   " is disabled\n"));
780                         return False;
781                 }
782
783                 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
784                     !lp_client_plaintext_auth() && (*pass)) {
785                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
786                                   " is disabled\n"));
787                         return False;
788                 }
789
790                 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
791         }
792
793         /* if no user is supplied then we have to do an anonymous connection.
794            passwords are ignored */
795
796         if (!user || !*user)
797                 return cli_session_setup_guest(cli);
798
799         /* if the server is share level then send a plaintext null
800            password at this point. The password is sent in the tree
801            connect */
802
803         if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) 
804                 return cli_session_setup_plaintext(cli, user, "", workgroup);
805
806         /* if the server doesn't support encryption then we have to use 
807            plaintext. The second password is ignored */
808
809         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
810                 if (!lp_client_plaintext_auth() && (*pass)) {
811                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
812                                   " is disabled\n"));
813                         return False;
814                 }
815                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
816         }
817
818         /* if the server supports extended security then use SPNEGO */
819
820         if (cli->capabilities & CAP_EXTENDED_SECURITY) {
821                 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, workgroup);
822                 if (!ADS_ERR_OK(status)) {
823                         DEBUG(3, ("SPENGO login failed: %s\n", ads_errstr(status)));
824                         return False;
825                 }
826                 return True;
827         }
828
829         /* otherwise do a NT1 style session setup */
830
831         return cli_session_setup_nt1(cli, user, 
832                                      pass, passlen, ntpass, ntpasslen,
833                                      workgroup);        
834 }
835
836 /****************************************************************************
837  Send a uloggoff.
838 *****************************************************************************/
839
840 BOOL cli_ulogoff(struct cli_state *cli)
841 {
842         memset(cli->outbuf,'\0',smb_size);
843         set_message(cli->outbuf,2,0,True);
844         SCVAL(cli->outbuf,smb_com,SMBulogoffX);
845         cli_setup_packet(cli);
846         SSVAL(cli->outbuf,smb_vwv0,0xFF);
847         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
848
849         cli_send_smb(cli);
850         if (!cli_receive_smb(cli))
851                 return False;
852
853         return !cli_is_error(cli);
854 }
855
856 /****************************************************************************
857  Send a tconX.
858 ****************************************************************************/
859 BOOL cli_send_tconX(struct cli_state *cli, 
860                     const char *share, const char *dev, const char *pass, int passlen)
861 {
862         fstring fullshare, pword;
863         char *p;
864         memset(cli->outbuf,'\0',smb_size);
865         memset(cli->inbuf,'\0',smb_size);
866
867         fstrcpy(cli->share, share);
868
869         /* in user level security don't send a password now */
870         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
871                 passlen = 1;
872                 pass = "";
873         }
874
875         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
876                 if (!lp_client_lanman_auth()) {
877                         DEBUG(1, ("Server requested LANMAN password but 'client use lanman auth'"
878                                   " is disabled\n"));
879                         return False;
880                 }
881
882                 /*
883                  * Non-encrypted passwords - convert to DOS codepage before encryption.
884                  */
885                 passlen = 24;
886                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
887         } else {
888                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
889                         if (!lp_client_plaintext_auth() && (*pass)) {
890                                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
891                                           " is disabled\n"));
892                                 return False;
893                         }
894
895                         /*
896                          * Non-encrypted passwords - convert to DOS codepage before using.
897                          */
898                         passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
899                         
900                 } else {
901                         memcpy(pword, pass, passlen);
902                 }
903         }
904
905         slprintf(fullshare, sizeof(fullshare)-1,
906                  "\\\\%s\\%s", cli->desthost, share);
907
908         set_message(cli->outbuf,4, 0, True);
909         SCVAL(cli->outbuf,smb_com,SMBtconX);
910         cli_setup_packet(cli);
911
912         SSVAL(cli->outbuf,smb_vwv0,0xFF);
913         SSVAL(cli->outbuf,smb_vwv3,passlen);
914
915         p = smb_buf(cli->outbuf);
916         memcpy(p,pword,passlen);
917         p += passlen;
918         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
919         p += clistr_push(cli, p, dev, -1, STR_TERMINATE |STR_UPPER | STR_ASCII);
920
921         cli_setup_bcc(cli, p);
922
923         cli_send_smb(cli);
924         if (!cli_receive_smb(cli))
925                 return False;
926
927         if (cli_is_error(cli))
928                 return False;
929
930         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
931
932         if (cli->protocol >= PROTOCOL_NT1 &&
933             smb_buflen(cli->inbuf) == 3) {
934                 /* almost certainly win95 - enable bug fixes */
935                 cli->win95 = True;
936         }
937
938         cli->cnum = SVAL(cli->inbuf,smb_tid);
939         return True;
940 }
941
942 /****************************************************************************
943  Send a tree disconnect.
944 ****************************************************************************/
945
946 BOOL cli_tdis(struct cli_state *cli)
947 {
948         memset(cli->outbuf,'\0',smb_size);
949         set_message(cli->outbuf,0,0,True);
950         SCVAL(cli->outbuf,smb_com,SMBtdis);
951         SSVAL(cli->outbuf,smb_tid,cli->cnum);
952         cli_setup_packet(cli);
953         
954         cli_send_smb(cli);
955         if (!cli_receive_smb(cli))
956                 return False;
957         
958         return !cli_is_error(cli);
959 }
960
961 /****************************************************************************
962  Send a negprot command.
963 ****************************************************************************/
964
965 void cli_negprot_send(struct cli_state *cli)
966 {
967         char *p;
968         int numprots;
969
970         if (cli->protocol < PROTOCOL_NT1)
971                 cli->use_spnego = False;
972
973         memset(cli->outbuf,'\0',smb_size);
974
975         /* setup the protocol strings */
976         set_message(cli->outbuf,0,0,True);
977
978         p = smb_buf(cli->outbuf);
979         for (numprots=0;
980              prots[numprots].name && prots[numprots].prot<=cli->protocol;
981              numprots++) {
982                 *p++ = 2;
983                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
984         }
985
986         SCVAL(cli->outbuf,smb_com,SMBnegprot);
987         cli_setup_bcc(cli, p);
988         cli_setup_packet(cli);
989
990         SCVAL(smb_buf(cli->outbuf),0,2);
991
992         cli_send_smb(cli);
993 }
994
995 /****************************************************************************
996  Send a negprot command.
997 ****************************************************************************/
998
999 BOOL cli_negprot(struct cli_state *cli)
1000 {
1001         char *p;
1002         int numprots;
1003         int plength;
1004
1005         if (cli->protocol < PROTOCOL_NT1)
1006                 cli->use_spnego = False;
1007
1008         memset(cli->outbuf,'\0',smb_size);
1009
1010         /* setup the protocol strings */
1011         for (plength=0,numprots=0;
1012              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1013              numprots++)
1014                 plength += strlen(prots[numprots].name)+2;
1015     
1016         set_message(cli->outbuf,0,plength,True);
1017
1018         p = smb_buf(cli->outbuf);
1019         for (numprots=0;
1020              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1021              numprots++) {
1022                 *p++ = 2;
1023                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1024         }
1025
1026         SCVAL(cli->outbuf,smb_com,SMBnegprot);
1027         cli_setup_packet(cli);
1028
1029         SCVAL(smb_buf(cli->outbuf),0,2);
1030
1031         cli_send_smb(cli);
1032         if (!cli_receive_smb(cli))
1033                 return False;
1034
1035         show_msg(cli->inbuf);
1036
1037         if (cli_is_error(cli) ||
1038             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
1039                 return(False);
1040         }
1041
1042         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
1043
1044         if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
1045                 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
1046                 return False;
1047         }
1048
1049         if (cli->protocol >= PROTOCOL_NT1) {    
1050                 /* NT protocol */
1051                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
1052                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
1053                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
1054                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
1055                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
1056                 cli->serverzone *= 60;
1057                 /* this time arrives in real GMT */
1058                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1059                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1060                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1061                 if (cli->capabilities & CAP_RAW_MODE) {
1062                         cli->readbraw_supported = True;
1063                         cli->writebraw_supported = True;      
1064                 }
1065                 /* work out if they sent us a workgroup */
1066                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1067                     smb_buflen(cli->inbuf) > 8) {
1068                         clistr_pull(cli, cli->server_domain, 
1069                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
1070                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
1071                 }
1072
1073                 /*
1074                  * As signing is slow we only turn it on if either the client or
1075                  * the server require it. JRA.
1076                  */
1077
1078                 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
1079                         /* Fail if server says signing is mandatory and we don't want to support it. */
1080                         if (!cli->sign_info.allow_smb_signing) {
1081                                 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1082                                 return False;
1083                         }
1084                         cli->sign_info.negotiated_smb_signing = True;
1085                         cli->sign_info.mandatory_signing = True;
1086                 } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
1087                         /* Fail if client says signing is mandatory and the server doesn't support it. */
1088                         if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
1089                                 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1090                                 return False;
1091                         }
1092                         cli->sign_info.negotiated_smb_signing = True;
1093                         cli->sign_info.mandatory_signing = True;
1094                 } else if (cli->sign_info.allow_smb_signing && cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
1095                         cli->sign_info.negotiated_smb_signing = True;
1096                 }
1097
1098         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1099                 cli->use_spnego = False;
1100                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
1101                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
1102                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
1103                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
1104                 cli->serverzone *= 60;
1105                 /* this time is converted to GMT by make_unix_date */
1106                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
1107                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
1108                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
1109                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1110         } else {
1111                 /* the old core protocol */
1112                 cli->use_spnego = False;
1113                 cli->sec_mode = 0;
1114                 cli->serverzone = TimeDiff(time(NULL));
1115         }
1116
1117         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1118
1119         /* a way to force ascii SMB */
1120         if (getenv("CLI_FORCE_ASCII"))
1121                 cli->capabilities &= ~CAP_UNICODE;
1122
1123         return True;
1124 }
1125
1126 /****************************************************************************
1127  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1128 ****************************************************************************/
1129
1130 BOOL cli_session_request(struct cli_state *cli,
1131                          struct nmb_name *calling, struct nmb_name *called)
1132 {
1133         char *p;
1134         int len = 4;
1135         extern pstring user_socket_options;
1136
1137         memcpy(&(cli->calling), calling, sizeof(*calling));
1138         memcpy(&(cli->called ), called , sizeof(*called ));
1139   
1140         /* put in the destination name */
1141         p = cli->outbuf+len;
1142         name_mangle(cli->called .name, p, cli->called .name_type);
1143         len += name_len(p);
1144
1145         /* and my name */
1146         p = cli->outbuf+len;
1147         name_mangle(cli->calling.name, p, cli->calling.name_type);
1148         len += name_len(p);
1149
1150         /* 445 doesn't have session request */
1151         if (cli->port == 445)
1152                 return True;
1153
1154         /* send a session request (RFC 1002) */
1155         /* setup the packet length
1156          * Remove four bytes from the length count, since the length
1157          * field in the NBT Session Service header counts the number
1158          * of bytes which follow.  The cli_send_smb() function knows
1159          * about this and accounts for those four bytes.
1160          * CRH.
1161          */
1162         len -= 4;
1163         _smb_setlen(cli->outbuf,len);
1164         SCVAL(cli->outbuf,0,0x81);
1165
1166         cli_send_smb(cli);
1167         DEBUG(5,("Sent session request\n"));
1168
1169         if (!cli_receive_smb(cli))
1170                 return False;
1171
1172         if (CVAL(cli->inbuf,0) == 0x84) {
1173                 /* C. Hoch  9/14/95 Start */
1174                 /* For information, here is the response structure.
1175                  * We do the byte-twiddling to for portability.
1176                 struct RetargetResponse{
1177                 unsigned char type;
1178                 unsigned char flags;
1179                 int16 length;
1180                 int32 ip_addr;
1181                 int16 port;
1182                 };
1183                 */
1184                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1185                 /* SESSION RETARGET */
1186                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1187
1188                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1189                 if (cli->fd == -1)
1190                         return False;
1191
1192                 DEBUG(3,("Retargeted\n"));
1193
1194                 set_socket_options(cli->fd,user_socket_options);
1195
1196                 /* Try again */
1197                 {
1198                         static int depth;
1199                         BOOL ret;
1200                         if (depth > 4) {
1201                                 DEBUG(0,("Retarget recursion - failing\n"));
1202                                 return False;
1203                         }
1204                         depth++;
1205                         ret = cli_session_request(cli, calling, called);
1206                         depth--;
1207                         return ret;
1208                 }
1209         } /* C. Hoch 9/14/95 End */
1210
1211         if (CVAL(cli->inbuf,0) != 0x82) {
1212                 /* This is the wrong place to put the error... JRA. */
1213                 cli->rap_error = CVAL(cli->inbuf,4);
1214                 return False;
1215         }
1216         return(True);
1217 }
1218
1219 /****************************************************************************
1220  Open the client sockets.
1221 ****************************************************************************/
1222
1223 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1224 {
1225         extern pstring user_socket_options;
1226         int name_type = 0x20;
1227         char *p;
1228
1229         /* reasonable default hostname */
1230         if (!host) host = "*SMBSERVER";
1231
1232         fstrcpy(cli->desthost, host);
1233
1234         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1235         if ((p = strchr(cli->desthost, '#'))) {
1236                 name_type = strtol(p+1, NULL, 16);              
1237                 *p = 0;
1238         }
1239         
1240         if (!ip || is_zero_ip(*ip)) {
1241                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1242                         return False;
1243                 }
1244                 if (ip) *ip = cli->dest_ip;
1245         } else {
1246                 cli->dest_ip = *ip;
1247         }
1248
1249         if (getenv("LIBSMB_PROG")) {
1250                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1251         } else {
1252                 /* try 445 first, then 139 */
1253                 int port = cli->port?cli->port:445;
1254                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1255                                           port, cli->timeout);
1256                 if (cli->fd == -1 && cli->port == 0) {
1257                         port = 139;
1258                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1259                                                   port, cli->timeout);
1260                 }
1261                 if (cli->fd != -1)
1262                         cli->port = port;
1263         }
1264         if (cli->fd == -1) {
1265                 DEBUG(1,("Error connecting to %s (%s)\n",
1266                          ip?inet_ntoa(*ip):host,strerror(errno)));
1267                 return False;
1268         }
1269
1270         set_socket_options(cli->fd,user_socket_options);
1271
1272         return True;
1273 }
1274
1275 /****************************************************************************
1276  Initialise client credentials for authenticated pipe access.
1277 ****************************************************************************/
1278
1279 void init_creds(struct ntuser_creds *creds, const char* username,
1280                        const char* domain, const char* password)
1281 {
1282         ZERO_STRUCTP(creds);
1283
1284         pwd_set_cleartext(&creds->pwd, password);
1285
1286         fstrcpy(creds->user_name, username);
1287         fstrcpy(creds->domain, domain);
1288
1289         if (!*username) {
1290                 creds->pwd.null_pwd = True;
1291         }
1292 }
1293
1294 /**
1295    establishes a connection to after the negprot. 
1296    @param output_cli A fully initialised cli structure, non-null only on success
1297    @param dest_host The netbios name of the remote host
1298    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1299    @param port (optional) The destination port (0 for default)
1300    @param retry BOOL. Did this connection fail with a retryable error ?
1301
1302 */
1303 NTSTATUS cli_start_connection(struct cli_state **output_cli, 
1304                               const char *my_name, 
1305                               const char *dest_host, 
1306                               struct in_addr *dest_ip, int port,
1307                               int signing_state, int flags,
1308                               BOOL *retry) 
1309 {
1310         NTSTATUS nt_status;
1311         struct nmb_name calling;
1312         struct nmb_name called;
1313         struct cli_state *cli;
1314         struct in_addr ip;
1315
1316         if (retry)
1317                 *retry = False;
1318
1319         if (!my_name) 
1320                 my_name = global_myname();
1321         
1322         if (!(cli = cli_initialise(NULL)))
1323                 return NT_STATUS_NO_MEMORY;
1324         
1325         make_nmb_name(&calling, my_name, 0x0);
1326         make_nmb_name(&called , dest_host, 0x20);
1327
1328         if (cli_set_port(cli, port) != port) {
1329                 cli_shutdown(cli);
1330                 return NT_STATUS_UNSUCCESSFUL;
1331         }
1332
1333         cli_set_timeout(cli, 10000); /* 10 seconds. */
1334
1335         if (dest_ip)
1336                 ip = *dest_ip;
1337         else
1338                 ZERO_STRUCT(ip);
1339
1340 again:
1341
1342         DEBUG(3,("Connecting to host=%s\n", dest_host));
1343         
1344         if (!cli_connect(cli, dest_host, &ip)) {
1345                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1346                          nmb_namestr(&called), inet_ntoa(ip)));
1347                 cli_shutdown(cli);
1348                 return NT_STATUS_UNSUCCESSFUL;
1349         }
1350
1351         if (retry)
1352                 *retry = True;
1353
1354         if (!cli_session_request(cli, &calling, &called)) {
1355                 char *p;
1356                 DEBUG(1,("session request to %s failed (%s)\n", 
1357                          called.name, cli_errstr(cli)));
1358                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1359                         *p = 0;
1360                         goto again;
1361                 }
1362                 if (strcmp(called.name, "*SMBSERVER")) {
1363                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1364                         goto again;
1365                 }
1366                 return NT_STATUS_UNSUCCESSFUL;
1367         }
1368
1369         cli_setup_signing_state(cli, signing_state);
1370
1371         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1372                 cli->use_spnego = False;
1373         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1374                 cli->use_kerberos = True;
1375
1376         if (!cli_negprot(cli)) {
1377                 DEBUG(1,("failed negprot\n"));
1378                 nt_status = NT_STATUS_UNSUCCESSFUL;
1379                 cli_shutdown(cli);
1380                 return nt_status;
1381         }
1382
1383         *output_cli = cli;
1384         return NT_STATUS_OK;
1385 }
1386
1387
1388 /**
1389    establishes a connection right up to doing tconX, password specified.
1390    @param output_cli A fully initialised cli structure, non-null only on success
1391    @param dest_host The netbios name of the remote host
1392    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1393    @param port (optional) The destination port (0 for default)
1394    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1395    @param service_type The 'type' of serivice. 
1396    @param user Username, unix string
1397    @param domain User's domain
1398    @param password User's password, unencrypted unix string.
1399    @param retry BOOL. Did this connection fail with a retryable error ?
1400 */
1401
1402 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1403                              const char *my_name, 
1404                              const char *dest_host, 
1405                              struct in_addr *dest_ip, int port,
1406                              const char *service, const char *service_type,
1407                              const char *user, const char *domain, 
1408                              const char *password, int flags,
1409                              int signing_state,
1410                              BOOL *retry) 
1411 {
1412         struct ntuser_creds creds;
1413         NTSTATUS nt_status;
1414         struct cli_state *cli = NULL;
1415
1416         nt_status = cli_start_connection(&cli, my_name, dest_host, 
1417                                          dest_ip, port, signing_state, flags, retry);
1418         
1419         if (!NT_STATUS_IS_OK(nt_status)) {
1420                 return nt_status;
1421         }
1422
1423         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1424                                password, strlen(password)+1, 
1425                                domain)) {
1426                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1427                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1428                 } else {
1429                         nt_status = cli_nt_error(cli);
1430                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1431                         cli_shutdown(cli);
1432                         if (NT_STATUS_IS_OK(nt_status)) 
1433                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1434                         return nt_status;
1435                 }
1436         } 
1437
1438         if (service) {
1439                 if (!cli_send_tconX(cli, service, service_type,
1440                                     password, strlen(password)+1)) {
1441                         nt_status = cli_nt_error(cli);
1442                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1443                         cli_shutdown(cli);
1444                         if (NT_STATUS_IS_OK(nt_status)) {
1445                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1446                         }
1447                         return nt_status;
1448                 }
1449         }
1450
1451         init_creds(&creds, user, domain, password);
1452         cli_init_creds(cli, &creds);
1453
1454         *output_cli = cli;
1455         return NT_STATUS_OK;
1456 }
1457
1458 /****************************************************************************
1459  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1460 ****************************************************************************/
1461
1462 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1463                                      struct in_addr *pdest_ip)
1464 {
1465         struct nmb_name calling, called;
1466
1467         make_nmb_name(&calling, srchost, 0x0);
1468
1469         /*
1470          * If the called name is an IP address
1471          * then use *SMBSERVER immediately.
1472          */
1473
1474         if(is_ipaddress(desthost))
1475                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1476         else
1477                 make_nmb_name(&called, desthost, 0x20);
1478
1479         if (!cli_session_request(cli, &calling, &called)) {
1480                 struct nmb_name smbservername;
1481
1482                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1483
1484                 /*
1485                  * If the name wasn't *SMBSERVER then
1486                  * try with *SMBSERVER if the first name fails.
1487                  */
1488
1489                 if (nmb_name_equal(&called, &smbservername)) {
1490
1491                         /*
1492                          * The name used was *SMBSERVER, don't bother with another name.
1493                          */
1494
1495                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1496 with error %s.\n", desthost, cli_errstr(cli) ));
1497                         return False;
1498                 }
1499
1500                 /*
1501                  * We need to close the connection here but can't call cli_shutdown as
1502                  * will free an allocated cli struct. cli_close_connection was invented
1503                  * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1504                  */
1505
1506                 cli_close_connection(cli);
1507
1508                 if (!cli_initialise(cli) ||
1509                                 !cli_connect(cli, desthost, pdest_ip) ||
1510                                 !cli_session_request(cli, &calling, &smbservername)) {
1511                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1512 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1513                         return False;
1514                 }
1515         }
1516
1517         return True;
1518 }
1519
1520
1521
1522
1523
1524 /****************************************************************************
1525  Send an old style tcon.
1526 ****************************************************************************/
1527 NTSTATUS cli_raw_tcon(struct cli_state *cli, 
1528                       const char *service, const char *pass, const char *dev,
1529                       uint16 *max_xmit, uint16 *tid)
1530 {
1531         char *p;
1532
1533         if (!lp_client_plaintext_auth() && (*pass)) {
1534                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1535                           " is disabled\n"));
1536                 return NT_STATUS_ACCESS_DENIED;
1537         }
1538
1539         memset(cli->outbuf,'\0',smb_size);
1540         memset(cli->inbuf,'\0',smb_size);
1541
1542         set_message(cli->outbuf, 0, 0, True);
1543         SCVAL(cli->outbuf,smb_com,SMBtcon);
1544         cli_setup_packet(cli);
1545
1546         p = smb_buf(cli->outbuf);
1547         *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
1548         *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
1549         *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
1550
1551         cli_setup_bcc(cli, p);
1552
1553         cli_send_smb(cli);
1554         if (!cli_receive_smb(cli)) {
1555                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1556         }
1557
1558         if (cli_is_error(cli)) {
1559                 return cli_nt_error(cli);
1560         }
1561
1562         *max_xmit = SVAL(cli->inbuf, smb_vwv0);
1563         *tid = SVAL(cli->inbuf, smb_vwv1);
1564
1565         return NT_STATUS_OK;
1566 }
1567
1568 /* Return a cli_state pointing at the IPC$ share for the given server */
1569
1570 struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
1571                                          struct user_auth_info *user_info)
1572 {
1573         struct cli_state *cli;
1574         pstring myname;
1575         NTSTATUS nt_status;
1576
1577         get_myname(myname);
1578         
1579         nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC", 
1580                                         user_info->username, lp_workgroup(), user_info->password, 
1581                                         CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, Undefined, NULL);
1582
1583         if (NT_STATUS_IS_OK(nt_status)) {
1584                 return cli;
1585         } else if (is_ipaddress(server)) {
1586             /* windows 9* needs a correct NMB name for connections */
1587             fstring remote_name;
1588
1589             if (name_status_find("*", 0, 0, *server_ip, remote_name)) {
1590                 cli = get_ipc_connect(remote_name, server_ip, user_info);
1591                 if (cli)
1592                     return cli;
1593             }
1594         }
1595         return NULL;
1596 }
1597
1598 /* Return the IP address and workgroup of a master browser on the 
1599    network. */
1600
1601 struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
1602 {
1603         struct ip_service *ip_list;
1604         struct cli_state *cli;
1605         int i, count;
1606         struct in_addr server_ip; 
1607
1608         /* Go looking for workgroups by broadcasting on the local network */ 
1609
1610         if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
1611                 return False;
1612         }
1613
1614         for (i = 0; i < count; i++) {
1615                 static fstring name;
1616
1617                 if (!name_status_find("*", 0, 0x1d, ip_list[i].ip, name))
1618                         continue;
1619
1620                 if (!find_master_ip(name, &server_ip))
1621                         continue;
1622
1623                 pstrcpy(workgroup, name);
1624
1625                 DEBUG(4, ("found master browser %s, %s\n", 
1626                           name, inet_ntoa(ip_list[i].ip)));
1627
1628                 cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
1629
1630                 if (!cli)
1631                     continue;
1632                 
1633                 return cli;
1634         }
1635
1636         return NULL;
1637 }