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