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