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