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