r17216: From Kai Blin <kai.blin@gmail.com>:
[samba.git] / source3 / libsmb / cliconnect.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client connect/disconnect routines
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Andrew Bartlett 2001-2003
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern pstring user_socket_options;
25
26 static const struct {
27         int prot;
28         const char *name;
29 } prots[] = {
30         {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
31         {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
32         {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
33         {PROTOCOL_LANMAN1,"LANMAN1.0"},
34         {PROTOCOL_LANMAN2,"LM1.2X002"},
35         {PROTOCOL_LANMAN2,"DOS LANMAN2.1"},
36         {PROTOCOL_LANMAN2,"Samba"},
37         {PROTOCOL_NT1,"NT LANMAN 1.0"},
38         {PROTOCOL_NT1,"NT LM 0.12"},
39         {-1,NULL}
40 };
41
42 /**
43  * Set the user session key for a connection
44  * @param cli The cli structure to add it too
45  * @param session_key The session key used.  (A copy of this is taken for the cli struct)
46  *
47  */
48
49 static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key) 
50 {
51         cli->user_session_key = data_blob(session_key.data, session_key.length);
52 }
53
54 /****************************************************************************
55  Do an old lanman2 style session setup.
56 ****************************************************************************/
57
58 static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user, 
59                                       const char *pass, size_t passlen, const char *workgroup)
60 {
61         DATA_BLOB session_key = data_blob(NULL, 0);
62         DATA_BLOB lm_response = data_blob(NULL, 0);
63         fstring pword;
64         char *p;
65
66         if (passlen > sizeof(pword)-1)
67                 return False;
68
69         /* LANMAN servers predate NT status codes and Unicode and ignore those 
70            smb flags so we must disable the corresponding default capabilities  
71            that would otherwise cause the Unicode and NT Status flags to be
72            set (and even returned by the server) */
73
74         cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
75
76         /* if in share level security then don't send a password now */
77         if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
78                 passlen = 0;
79
80         if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
81                 /* Encrypted mode needed, and non encrypted password supplied. */
82                 lm_response = data_blob(NULL, 24);
83                 if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
84                         DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
85                         return False;
86                 }
87         } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
88                 /* Encrypted mode needed, and encrypted password supplied. */
89                 lm_response = data_blob(pass, passlen);
90         } else if (passlen > 0) {
91                 /* Plaintext mode needed, assume plaintext supplied. */
92                 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
93                 lm_response = data_blob(pass, passlen);
94         }
95
96         /* send a session setup command */
97         memset(cli->outbuf,'\0',smb_size);
98         set_message(cli->outbuf,10, 0, True);
99         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
100         cli_setup_packet(cli);
101         
102         SCVAL(cli->outbuf,smb_vwv0,0xFF);
103         SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
104         SSVAL(cli->outbuf,smb_vwv3,2);
105         SSVAL(cli->outbuf,smb_vwv4,1);
106         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
107         SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
108
109         p = smb_buf(cli->outbuf);
110         memcpy(p,lm_response.data,lm_response.length);
111         p += lm_response.length;
112         p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
113         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
114         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
115         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
116         cli_setup_bcc(cli, p);
117
118         cli_send_smb(cli);
119         if (!cli_receive_smb(cli))
120                 return False;
121
122         show_msg(cli->inbuf);
123
124         if (cli_is_error(cli))
125                 return False;
126         
127         /* use the returned vuid from now on */
128         cli->vuid = SVAL(cli->inbuf,smb_uid);   
129         fstrcpy(cli->user_name, user);
130
131         if (session_key.data) {
132                 /* Have plaintext orginal */
133                 cli_set_session_key(cli, session_key);
134         }
135
136         return True;
137 }
138
139 /****************************************************************************
140  Work out suitable capabilities to offer the server.
141 ****************************************************************************/
142
143 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
144 {
145         uint32 capabilities = CAP_NT_SMBS;
146
147         if (!cli->force_dos_errors)
148                 capabilities |= CAP_STATUS32;
149
150         if (cli->use_level_II_oplocks)
151                 capabilities |= CAP_LEVEL_II_OPLOCKS;
152
153         capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
154         return capabilities;
155 }
156
157 /****************************************************************************
158  Do a NT1 guest session setup.
159 ****************************************************************************/
160
161 static BOOL cli_session_setup_guest(struct cli_state *cli)
162 {
163         char *p;
164         uint32 capabilities = cli_session_setup_capabilities(cli);
165
166         memset(cli->outbuf, '\0', smb_size);
167         set_message(cli->outbuf,13,0,True);
168         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
169         cli_setup_packet(cli);
170                         
171         SCVAL(cli->outbuf,smb_vwv0,0xFF);
172         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
173         SSVAL(cli->outbuf,smb_vwv3,2);
174         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
175         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
176         SSVAL(cli->outbuf,smb_vwv7,0);
177         SSVAL(cli->outbuf,smb_vwv8,0);
178         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
179         p = smb_buf(cli->outbuf);
180         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
181         p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
182         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
183         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
184         cli_setup_bcc(cli, p);
185
186         cli_send_smb(cli);
187         if (!cli_receive_smb(cli))
188               return False;
189         
190         show_msg(cli->inbuf);
191         
192         if (cli_is_error(cli))
193                 return False;
194
195         cli->vuid = SVAL(cli->inbuf,smb_uid);
196
197         p = smb_buf(cli->inbuf);
198         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
199         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
200         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
201
202         if (strstr(cli->server_type, "Samba")) {
203                 cli->is_samba = True;
204         }
205
206         fstrcpy(cli->user_name, "");
207
208         return True;
209 }
210
211 /****************************************************************************
212  Do a NT1 plaintext session setup.
213 ****************************************************************************/
214
215 static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user, 
216                                         const char *pass, const char *workgroup)
217 {
218         uint32 capabilities = cli_session_setup_capabilities(cli);
219         char *p;
220         fstring lanman;
221         
222         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
223
224         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         ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
603
604         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
605                 return nt_status;
606         }
607         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
608                 return nt_status;
609         }
610         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
611                 return nt_status;
612         }
613
614         do {
615                 nt_status = ntlmssp_update(ntlmssp_state, 
616                                                   blob_in, &blob_out);
617                 data_blob_free(&blob_in);
618                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) {
619                         if (turn == 1) {
620                                 /* and wrap it in a SPNEGO wrapper */
621                                 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
622                         } else {
623                                 /* wrap it in SPNEGO */
624                                 msg1 = spnego_gen_auth(blob_out);
625                         }
626                 
627                         /* now send that blob on its way */
628                         if (!cli_session_setup_blob_send(cli, msg1)) {
629                                 DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
630                                 nt_status = NT_STATUS_UNSUCCESSFUL;
631                         } else {
632                                 data_blob_free(&msg1);
633                                 
634                                 blob = cli_session_setup_blob_receive(cli);
635                                 
636                                 nt_status = cli_nt_error(cli);
637                                 if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
638                                         if (cli->smb_rw_error == READ_BAD_SIG) {
639                                                 nt_status = NT_STATUS_ACCESS_DENIED;
640                                         } else {
641                                                 nt_status = NT_STATUS_UNSUCCESSFUL;
642                                         }
643                                 }
644                         }
645                 }
646                 
647                 if (!blob.length) {
648                         if (NT_STATUS_IS_OK(nt_status)) {
649                                 nt_status = NT_STATUS_UNSUCCESSFUL;
650                         }
651                 } else if ((turn == 1) && 
652                            NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
653                         DATA_BLOB tmp_blob = data_blob(NULL, 0);
654                         /* the server might give us back two challenges */
655                         if (!spnego_parse_challenge(blob, &blob_in, 
656                                                     &tmp_blob)) {
657                                 DEBUG(3,("Failed to parse challenges\n"));
658                                 nt_status = NT_STATUS_INVALID_PARAMETER;
659                         }
660                         data_blob_free(&tmp_blob);
661                 } else {
662                         if (!spnego_parse_auth_response(blob, nt_status, 
663                                                         &blob_in)) {
664                                 DEBUG(3,("Failed to parse auth response\n"));
665                                 if (NT_STATUS_IS_OK(nt_status) 
666                                     || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) 
667                                         nt_status = NT_STATUS_INVALID_PARAMETER;
668                         }
669                 }
670                 data_blob_free(&blob);
671                 data_blob_free(&blob_out);
672                 turn++;
673         } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
674
675         if (NT_STATUS_IS_OK(nt_status)) {
676
677                 DATA_BLOB key = data_blob(ntlmssp_state->session_key.data,
678                                           ntlmssp_state->session_key.length);
679                 DATA_BLOB null_blob = data_blob(NULL, 0);
680                 BOOL res;
681
682                 fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
683                 cli_set_session_key(cli, ntlmssp_state->session_key);
684
685                 res = cli_simple_set_signing(cli, key, null_blob);
686
687                 data_blob_free(&key);
688
689                 if (res) {
690                         
691                         /* 'resign' the last message, so we get the right sequence numbers
692                            for checking the first reply from the server */
693                         cli_calculate_sign_mac(cli);
694                         
695                         if (!cli_check_sign_mac(cli)) {
696                                 nt_status = NT_STATUS_ACCESS_DENIED;
697                         }
698                 }
699         }
700
701         /* we have a reference conter on ntlmssp_state, if we are signing
702            then the state will be kept by the signing engine */
703
704         ntlmssp_end(&ntlmssp_state);
705
706         return nt_status;
707 }
708
709 /****************************************************************************
710  Do a spnego encrypted session setup.
711 ****************************************************************************/
712
713 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, 
714                               const char *pass, const char *domain)
715 {
716         char *principal;
717         char *OIDs[ASN1_MAX_OIDS];
718         int i;
719 #ifdef HAVE_KRB5
720         BOOL got_kerberos_mechanism = False;
721 #endif
722         DATA_BLOB blob;
723
724         DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
725
726         /* the server might not even do spnego */
727         if (cli->secblob.length <= 16) {
728                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
729                 goto ntlmssp;
730         }
731
732 #if 0
733         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
734 #endif
735
736         /* there is 16 bytes of GUID before the real spnego packet starts */
737         blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
738
739         /* the server sent us the first part of the SPNEGO exchange in the negprot 
740            reply */
741         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
742                 data_blob_free(&blob);
743                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
744         }
745         data_blob_free(&blob);
746
747         /* make sure the server understands kerberos */
748         for (i=0;OIDs[i];i++) {
749                 DEBUG(3,("got OID=%s\n", OIDs[i]));
750 #ifdef HAVE_KRB5
751                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
752                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
753                         got_kerberos_mechanism = True;
754                 }
755 #endif
756                 free(OIDs[i]);
757         }
758         DEBUG(3,("got principal=%s\n", principal));
759
760         fstrcpy(cli->user_name, user);
761
762 #ifdef HAVE_KRB5
763         /* If password is set we reauthenticate to kerberos server
764          * and do not store results */
765
766         if (got_kerberos_mechanism && cli->use_kerberos) {
767                 ADS_STATUS rc;
768
769                 if (pass && *pass) {
770                         int ret;
771                         
772                         use_in_memory_ccache();
773                         ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
774                         
775                         if (ret){
776                                 SAFE_FREE(principal);
777                                 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
778                                 if (cli->fallback_after_kerberos)
779                                         goto ntlmssp;
780                                 return ADS_ERROR_KRB5(ret);
781                         }
782                 }
783                 
784                 rc = cli_session_setup_kerberos(cli, principal, domain);
785                 if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
786                         SAFE_FREE(principal);
787                         return rc;
788                 }
789         }
790 #endif
791
792         SAFE_FREE(principal);
793
794 ntlmssp:
795
796         return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, user, pass, domain));
797 }
798
799 /****************************************************************************
800  Send a session setup. The username and workgroup is in UNIX character
801  format and must be converted to DOS codepage format before sending. If the
802  password is in plaintext, the same should be done.
803 ****************************************************************************/
804
805 BOOL cli_session_setup(struct cli_state *cli, 
806                        const char *user, 
807                        const char *pass, int passlen,
808                        const char *ntpass, int ntpasslen,
809                        const char *workgroup)
810 {
811         char *p;
812         fstring user2;
813
814         /* allow for workgroups as part of the username */
815         fstrcpy(user2, user);
816         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
817             (p=strchr_m(user2,*lp_winbind_separator()))) {
818                 *p = 0;
819                 user = p+1;
820                 workgroup = user2;
821         }
822
823         if (cli->protocol < PROTOCOL_LANMAN1)
824                 return True;
825
826         /* now work out what sort of session setup we are going to
827            do. I have split this into separate functions to make the
828            flow a bit easier to understand (tridge) */
829
830         /* if its an older server then we have to use the older request format */
831
832         if (cli->protocol < PROTOCOL_NT1) {
833                 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
834                         DEBUG(1, ("Server requested LM password but 'client lanman auth'"
835                                   " is disabled\n"));
836                         return False;
837                 }
838
839                 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
840                     !lp_client_plaintext_auth() && (*pass)) {
841                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
842                                   " is disabled\n"));
843                         return False;
844                 }
845
846                 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
847         }
848
849         /* if no user is supplied then we have to do an anonymous connection.
850            passwords are ignored */
851
852         if (!user || !*user)
853                 return cli_session_setup_guest(cli);
854
855         /* if the server is share level then send a plaintext null
856            password at this point. The password is sent in the tree
857            connect */
858
859         if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) 
860                 return cli_session_setup_plaintext(cli, user, "", workgroup);
861
862         /* if the server doesn't support encryption then we have to use 
863            plaintext. The second password is ignored */
864
865         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
866                 if (!lp_client_plaintext_auth() && (*pass)) {
867                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
868                                   " is disabled\n"));
869                         return False;
870                 }
871                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
872         }
873
874         /* if the server supports extended security then use SPNEGO */
875
876         if (cli->capabilities & CAP_EXTENDED_SECURITY) {
877                 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, workgroup);
878                 if (!ADS_ERR_OK(status)) {
879                         DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
880                         return False;
881                 }
882         } else {
883                 /* otherwise do a NT1 style session setup */
884                 if ( !cli_session_setup_nt1(cli, user, pass, passlen, ntpass, ntpasslen, workgroup) ) {
885                         DEBUG(3,("cli_session_setup: NT1 session setup failed!\n"));
886                         return False;
887                 }
888         }
889
890         if (strstr(cli->server_type, "Samba")) {
891                 cli->is_samba = True;
892         }
893
894         return True;
895
896 }
897
898 /****************************************************************************
899  Send a uloggoff.
900 *****************************************************************************/
901
902 BOOL cli_ulogoff(struct cli_state *cli)
903 {
904         memset(cli->outbuf,'\0',smb_size);
905         set_message(cli->outbuf,2,0,True);
906         SCVAL(cli->outbuf,smb_com,SMBulogoffX);
907         cli_setup_packet(cli);
908         SSVAL(cli->outbuf,smb_vwv0,0xFF);
909         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
910
911         cli_send_smb(cli);
912         if (!cli_receive_smb(cli))
913                 return False;
914
915         if (cli_is_error(cli)) {
916                 return False;
917         }
918
919         cli->cnum = -1;
920         return True;
921 }
922
923 /****************************************************************************
924  Send a tconX.
925 ****************************************************************************/
926
927 BOOL cli_send_tconX(struct cli_state *cli, 
928                     const char *share, const char *dev, const char *pass, int passlen)
929 {
930         fstring fullshare, pword;
931         char *p;
932         memset(cli->outbuf,'\0',smb_size);
933         memset(cli->inbuf,'\0',smb_size);
934
935         fstrcpy(cli->share, share);
936
937         /* in user level security don't send a password now */
938         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
939                 passlen = 1;
940                 pass = "";
941         } else if (!pass) {
942                 DEBUG(1, ("Server not using user level security and no password supplied.\n"));
943                 return False;
944         }
945
946         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
947             *pass && passlen != 24) {
948                 if (!lp_client_lanman_auth()) {
949                         DEBUG(1, ("Server requested LANMAN password (share-level security) but 'client use lanman auth'"
950                                   " is disabled\n"));
951                         return False;
952                 }
953
954                 /*
955                  * Non-encrypted passwords - convert to DOS codepage before encryption.
956                  */
957                 passlen = 24;
958                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
959         } else {
960                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
961                         if (!lp_client_plaintext_auth() && (*pass)) {
962                                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
963                                           " is disabled\n"));
964                                 return False;
965                         }
966
967                         /*
968                          * Non-encrypted passwords - convert to DOS codepage before using.
969                          */
970                         passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
971                         
972                 } else {
973                         if (passlen) {
974                                 memcpy(pword, pass, passlen);
975                         }
976                 }
977         }
978
979         slprintf(fullshare, sizeof(fullshare)-1,
980                  "\\\\%s\\%s", cli->desthost, share);
981
982         set_message(cli->outbuf,4, 0, True);
983         SCVAL(cli->outbuf,smb_com,SMBtconX);
984         cli_setup_packet(cli);
985
986         SSVAL(cli->outbuf,smb_vwv0,0xFF);
987         SSVAL(cli->outbuf,smb_vwv3,passlen);
988
989         p = smb_buf(cli->outbuf);
990         if (passlen) {
991                 memcpy(p,pword,passlen);
992         }
993         p += passlen;
994         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
995         p += clistr_push(cli, p, dev, -1, STR_TERMINATE |STR_UPPER | STR_ASCII);
996
997         cli_setup_bcc(cli, p);
998
999         cli_send_smb(cli);
1000         if (!cli_receive_smb(cli))
1001                 return False;
1002
1003         if (cli_is_error(cli))
1004                 return False;
1005
1006         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
1007
1008         if (cli->protocol >= PROTOCOL_NT1 &&
1009             smb_buflen(cli->inbuf) == 3) {
1010                 /* almost certainly win95 - enable bug fixes */
1011                 cli->win95 = True;
1012         }
1013         
1014         /* Make sure that we have the optional support 16-bit field.  WCT > 2 */
1015         /* Avoids issues when connecting to Win9x boxes sharing files */
1016
1017         cli->dfsroot = False;
1018         if ( (CVAL(cli->inbuf, smb_wct))>2 && cli->protocol >= PROTOCOL_LANMAN2 )
1019                 cli->dfsroot = (SVAL( cli->inbuf, smb_vwv2 ) & SMB_SHARE_IN_DFS) ? True : False;
1020
1021         cli->cnum = SVAL(cli->inbuf,smb_tid);
1022         return True;
1023 }
1024
1025 /****************************************************************************
1026  Send a tree disconnect.
1027 ****************************************************************************/
1028
1029 BOOL cli_tdis(struct cli_state *cli)
1030 {
1031         memset(cli->outbuf,'\0',smb_size);
1032         set_message(cli->outbuf,0,0,True);
1033         SCVAL(cli->outbuf,smb_com,SMBtdis);
1034         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1035         cli_setup_packet(cli);
1036         
1037         cli_send_smb(cli);
1038         if (!cli_receive_smb(cli))
1039                 return False;
1040         
1041         if (cli_is_error(cli)) {
1042                 return False;
1043         }
1044
1045         cli->cnum = -1;
1046         return True;
1047 }
1048
1049 /****************************************************************************
1050  Send a negprot command.
1051 ****************************************************************************/
1052
1053 void cli_negprot_send(struct cli_state *cli)
1054 {
1055         char *p;
1056         int numprots;
1057
1058         if (cli->protocol < PROTOCOL_NT1)
1059                 cli->use_spnego = False;
1060
1061         memset(cli->outbuf,'\0',smb_size);
1062
1063         /* setup the protocol strings */
1064         set_message(cli->outbuf,0,0,True);
1065
1066         p = smb_buf(cli->outbuf);
1067         for (numprots=0;
1068              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1069              numprots++) {
1070                 *p++ = 2;
1071                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1072         }
1073
1074         SCVAL(cli->outbuf,smb_com,SMBnegprot);
1075         cli_setup_bcc(cli, p);
1076         cli_setup_packet(cli);
1077
1078         SCVAL(smb_buf(cli->outbuf),0,2);
1079
1080         cli_send_smb(cli);
1081 }
1082
1083 /****************************************************************************
1084  Send a negprot command.
1085 ****************************************************************************/
1086
1087 BOOL cli_negprot(struct cli_state *cli)
1088 {
1089         char *p;
1090         int numprots;
1091         int plength;
1092
1093         if (cli->protocol < PROTOCOL_NT1)
1094                 cli->use_spnego = False;
1095
1096         memset(cli->outbuf,'\0',smb_size);
1097
1098         /* setup the protocol strings */
1099         for (plength=0,numprots=0;
1100              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1101              numprots++)
1102                 plength += strlen(prots[numprots].name)+2;
1103     
1104         set_message(cli->outbuf,0,plength,True);
1105
1106         p = smb_buf(cli->outbuf);
1107         for (numprots=0;
1108              prots[numprots].name && prots[numprots].prot<=cli->protocol;
1109              numprots++) {
1110                 *p++ = 2;
1111                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1112         }
1113
1114         SCVAL(cli->outbuf,smb_com,SMBnegprot);
1115         cli_setup_packet(cli);
1116
1117         SCVAL(smb_buf(cli->outbuf),0,2);
1118
1119         cli_send_smb(cli);
1120         if (!cli_receive_smb(cli))
1121                 return False;
1122
1123         show_msg(cli->inbuf);
1124
1125         if (cli_is_error(cli) ||
1126             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
1127                 return(False);
1128         }
1129
1130         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
1131
1132         if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
1133                 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
1134                 return False;
1135         }
1136
1137         if (cli->protocol >= PROTOCOL_NT1) {    
1138                 /* NT protocol */
1139                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
1140                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
1141                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
1142                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
1143                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
1144                 cli->serverzone *= 60;
1145                 /* this time arrives in real GMT */
1146                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1147                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1148                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1149                 if (cli->capabilities & CAP_RAW_MODE) {
1150                         cli->readbraw_supported = True;
1151                         cli->writebraw_supported = True;      
1152                 }
1153                 /* work out if they sent us a workgroup */
1154                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1155                     smb_buflen(cli->inbuf) > 8) {
1156                         clistr_pull(cli, cli->server_domain, 
1157                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
1158                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
1159                 }
1160
1161                 /*
1162                  * As signing is slow we only turn it on if either the client or
1163                  * the server require it. JRA.
1164                  */
1165
1166                 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
1167                         /* Fail if server says signing is mandatory and we don't want to support it. */
1168                         if (!cli->sign_info.allow_smb_signing) {
1169                                 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1170                                 return False;
1171                         }
1172                         cli->sign_info.negotiated_smb_signing = True;
1173                         cli->sign_info.mandatory_signing = True;
1174                 } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
1175                         /* Fail if client says signing is mandatory and the server doesn't support it. */
1176                         if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
1177                                 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1178                                 return False;
1179                         }
1180                         cli->sign_info.negotiated_smb_signing = True;
1181                         cli->sign_info.mandatory_signing = True;
1182                 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
1183                         cli->sign_info.negotiated_smb_signing = True;
1184                 }
1185
1186                 if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
1187                         SAFE_FREE(cli->outbuf);
1188                         SAFE_FREE(cli->inbuf);
1189                         cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
1190                         cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+SAFETY_MARGIN);
1191                         cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
1192                 }
1193
1194         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1195                 cli->use_spnego = False;
1196                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
1197                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
1198                 cli->max_mux = SVAL(cli->inbuf, smb_vwv3); 
1199                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
1200                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
1201                 cli->serverzone *= 60;
1202                 /* this time is converted to GMT by make_unix_date */
1203                 cli->servertime = cli_make_unix_date(cli,cli->inbuf+smb_vwv8);
1204                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
1205                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
1206                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1207         } else {
1208                 /* the old core protocol */
1209                 cli->use_spnego = False;
1210                 cli->sec_mode = 0;
1211                 cli->serverzone = get_time_zone(time(NULL));
1212         }
1213
1214         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1215
1216         /* a way to force ascii SMB */
1217         if (getenv("CLI_FORCE_ASCII"))
1218                 cli->capabilities &= ~CAP_UNICODE;
1219
1220         return True;
1221 }
1222
1223 /****************************************************************************
1224  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1225 ****************************************************************************/
1226
1227 BOOL cli_session_request(struct cli_state *cli,
1228                          struct nmb_name *calling, struct nmb_name *called)
1229 {
1230         char *p;
1231         int len = 4;
1232
1233         memcpy(&(cli->calling), calling, sizeof(*calling));
1234         memcpy(&(cli->called ), called , sizeof(*called ));
1235   
1236         /* put in the destination name */
1237         p = cli->outbuf+len;
1238         name_mangle(cli->called .name, p, cli->called .name_type);
1239         len += name_len(p);
1240
1241         /* and my name */
1242         p = cli->outbuf+len;
1243         name_mangle(cli->calling.name, p, cli->calling.name_type);
1244         len += name_len(p);
1245
1246         /* 445 doesn't have session request */
1247         if (cli->port == 445)
1248                 return True;
1249
1250         /* send a session request (RFC 1002) */
1251         /* setup the packet length
1252          * Remove four bytes from the length count, since the length
1253          * field in the NBT Session Service header counts the number
1254          * of bytes which follow.  The cli_send_smb() function knows
1255          * about this and accounts for those four bytes.
1256          * CRH.
1257          */
1258         len -= 4;
1259         _smb_setlen(cli->outbuf,len);
1260         SCVAL(cli->outbuf,0,0x81);
1261
1262         cli_send_smb(cli);
1263         DEBUG(5,("Sent session request\n"));
1264
1265         if (!cli_receive_smb(cli))
1266                 return False;
1267
1268         if (CVAL(cli->inbuf,0) == 0x84) {
1269                 /* C. Hoch  9/14/95 Start */
1270                 /* For information, here is the response structure.
1271                  * We do the byte-twiddling to for portability.
1272                 struct RetargetResponse{
1273                 unsigned char type;
1274                 unsigned char flags;
1275                 int16 length;
1276                 int32 ip_addr;
1277                 int16 port;
1278                 };
1279                 */
1280                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1281                 /* SESSION RETARGET */
1282                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1283
1284                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1285                 if (cli->fd == -1)
1286                         return False;
1287
1288                 DEBUG(3,("Retargeted\n"));
1289
1290                 set_socket_options(cli->fd,user_socket_options);
1291
1292                 /* Try again */
1293                 {
1294                         static int depth;
1295                         BOOL ret;
1296                         if (depth > 4) {
1297                                 DEBUG(0,("Retarget recursion - failing\n"));
1298                                 return False;
1299                         }
1300                         depth++;
1301                         ret = cli_session_request(cli, calling, called);
1302                         depth--;
1303                         return ret;
1304                 }
1305         } /* C. Hoch 9/14/95 End */
1306
1307         if (CVAL(cli->inbuf,0) != 0x82) {
1308                 /* This is the wrong place to put the error... JRA. */
1309                 cli->rap_error = CVAL(cli->inbuf,4);
1310                 return False;
1311         }
1312         return(True);
1313 }
1314
1315 /****************************************************************************
1316  Open the client sockets.
1317 ****************************************************************************/
1318
1319 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1320 {
1321         int name_type = 0x20;
1322         char *p;
1323
1324         /* reasonable default hostname */
1325         if (!host) host = "*SMBSERVER";
1326
1327         fstrcpy(cli->desthost, host);
1328
1329         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1330         if ((p = strchr(cli->desthost, '#'))) {
1331                 name_type = strtol(p+1, NULL, 16);              
1332                 *p = 0;
1333         }
1334         
1335         if (!ip || is_zero_ip(*ip)) {
1336                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1337                         return False;
1338                 }
1339                 if (ip) *ip = cli->dest_ip;
1340         } else {
1341                 cli->dest_ip = *ip;
1342         }
1343
1344         if (getenv("LIBSMB_PROG")) {
1345                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1346         } else {
1347                 /* try 445 first, then 139 */
1348                 int port = cli->port?cli->port:445;
1349                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1350                                           port, cli->timeout);
1351                 if (cli->fd == -1 && cli->port == 0) {
1352                         port = 139;
1353                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1354                                                   port, cli->timeout);
1355                 }
1356                 if (cli->fd != -1)
1357                         cli->port = port;
1358         }
1359         if (cli->fd == -1) {
1360                 DEBUG(1,("Error connecting to %s (%s)\n",
1361                          ip?inet_ntoa(*ip):host,strerror(errno)));
1362                 return False;
1363         }
1364
1365         set_socket_options(cli->fd,user_socket_options);
1366
1367         return True;
1368 }
1369
1370 /**
1371    establishes a connection to after the negprot. 
1372    @param output_cli A fully initialised cli structure, non-null only on success
1373    @param dest_host The netbios name of the remote host
1374    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1375    @param port (optional) The destination port (0 for default)
1376    @param retry BOOL. Did this connection fail with a retryable error ?
1377
1378 */
1379 NTSTATUS cli_start_connection(struct cli_state **output_cli, 
1380                               const char *my_name, 
1381                               const char *dest_host, 
1382                               struct in_addr *dest_ip, int port,
1383                               int signing_state, int flags,
1384                               BOOL *retry) 
1385 {
1386         NTSTATUS nt_status;
1387         struct nmb_name calling;
1388         struct nmb_name called;
1389         struct cli_state *cli;
1390         struct in_addr ip;
1391
1392         if (retry)
1393                 *retry = False;
1394
1395         if (!my_name) 
1396                 my_name = global_myname();
1397         
1398         if (!(cli = cli_initialise())) {
1399                 return NT_STATUS_NO_MEMORY;
1400         }
1401         
1402         make_nmb_name(&calling, my_name, 0x0);
1403         make_nmb_name(&called , dest_host, 0x20);
1404
1405         if (cli_set_port(cli, port) != port) {
1406                 cli_shutdown(cli);
1407                 return NT_STATUS_UNSUCCESSFUL;
1408         }
1409
1410         cli_set_timeout(cli, 10000); /* 10 seconds. */
1411
1412         if (dest_ip)
1413                 ip = *dest_ip;
1414         else
1415                 ZERO_STRUCT(ip);
1416
1417 again:
1418
1419         DEBUG(3,("Connecting to host=%s\n", dest_host));
1420         
1421         if (!cli_connect(cli, dest_host, &ip)) {
1422                 DEBUG(1,("cli_start_connection: failed to connect to %s (%s)\n",
1423                          nmb_namestr(&called), inet_ntoa(ip)));
1424                 cli_shutdown(cli);
1425                 if (is_zero_ip(ip)) {
1426                         return NT_STATUS_BAD_NETWORK_NAME;
1427                 } else {
1428                         return NT_STATUS_CONNECTION_REFUSED;
1429                 }
1430         }
1431
1432         if (retry)
1433                 *retry = True;
1434
1435         if (!cli_session_request(cli, &calling, &called)) {
1436                 char *p;
1437                 DEBUG(1,("session request to %s failed (%s)\n", 
1438                          called.name, cli_errstr(cli)));
1439                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1440                         *p = 0;
1441                         goto again;
1442                 }
1443                 if (strcmp(called.name, "*SMBSERVER")) {
1444                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1445                         goto again;
1446                 }
1447                 return NT_STATUS_BAD_NETWORK_NAME;
1448         }
1449
1450         cli_setup_signing_state(cli, signing_state);
1451
1452         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1453                 cli->use_spnego = False;
1454         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1455                 cli->use_kerberos = True;
1456
1457         if (!cli_negprot(cli)) {
1458                 DEBUG(1,("failed negprot\n"));
1459                 nt_status = cli_nt_error(cli);
1460                 if (NT_STATUS_IS_OK(nt_status)) {
1461                         nt_status = NT_STATUS_UNSUCCESSFUL;
1462                 }
1463                 cli_shutdown(cli);
1464                 return nt_status;
1465         }
1466
1467         *output_cli = cli;
1468         return NT_STATUS_OK;
1469 }
1470
1471
1472 /**
1473    establishes a connection right up to doing tconX, password specified.
1474    @param output_cli A fully initialised cli structure, non-null only on success
1475    @param dest_host The netbios name of the remote host
1476    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1477    @param port (optional) The destination port (0 for default)
1478    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1479    @param service_type The 'type' of serivice. 
1480    @param user Username, unix string
1481    @param domain User's domain
1482    @param password User's password, unencrypted unix string.
1483    @param retry BOOL. Did this connection fail with a retryable error ?
1484 */
1485
1486 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1487                              const char *my_name, 
1488                              const char *dest_host, 
1489                              struct in_addr *dest_ip, int port,
1490                              const char *service, const char *service_type,
1491                              const char *user, const char *domain, 
1492                              const char *password, int flags,
1493                              int signing_state,
1494                              BOOL *retry) 
1495 {
1496         NTSTATUS nt_status;
1497         struct cli_state *cli = NULL;
1498         int pw_len = password ? strlen(password)+1 : 0;
1499
1500         *output_cli = NULL;
1501
1502         if (password == NULL) {
1503                 password = "";
1504         }
1505
1506         nt_status = cli_start_connection(&cli, my_name, dest_host, 
1507                                          dest_ip, port, signing_state, flags, retry);
1508         
1509         if (!NT_STATUS_IS_OK(nt_status)) {
1510                 return nt_status;
1511         }
1512
1513         if (!cli_session_setup(cli, user, password, pw_len, password, pw_len, domain)) {
1514                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1515                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1516                 } else {
1517                         nt_status = cli_nt_error(cli);
1518                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1519                         cli_shutdown(cli);
1520                         if (NT_STATUS_IS_OK(nt_status)) {
1521                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1522                         }
1523                         return nt_status;
1524                 }
1525         } 
1526
1527         if (service) {
1528                 if (!cli_send_tconX(cli, service, service_type, password, pw_len)) {
1529                         nt_status = cli_nt_error(cli);
1530                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1531                         cli_shutdown(cli);
1532                         if (NT_STATUS_IS_OK(nt_status)) {
1533                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1534                         }
1535                         return nt_status;
1536                 }
1537         }
1538
1539         cli_init_creds(cli, user, domain, password);
1540
1541         *output_cli = cli;
1542         return NT_STATUS_OK;
1543 }
1544
1545 /****************************************************************************
1546  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1547 ****************************************************************************/
1548
1549 BOOL attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
1550                                      struct in_addr *pdest_ip)
1551 {
1552         struct nmb_name calling, called;
1553
1554         make_nmb_name(&calling, srchost, 0x0);
1555
1556         /*
1557          * If the called name is an IP address
1558          * then use *SMBSERVER immediately.
1559          */
1560
1561         if(is_ipaddress(desthost)) {
1562                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1563         } else {
1564                 make_nmb_name(&called, desthost, 0x20);
1565         }
1566
1567         if (!cli_session_request(*ppcli, &calling, &called)) {
1568                 struct nmb_name smbservername;
1569
1570                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1571
1572                 /*
1573                  * If the name wasn't *SMBSERVER then
1574                  * try with *SMBSERVER if the first name fails.
1575                  */
1576
1577                 if (nmb_name_equal(&called, &smbservername)) {
1578
1579                         /*
1580                          * The name used was *SMBSERVER, don't bother with another name.
1581                          */
1582
1583                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1584 with error %s.\n", desthost, cli_errstr(*ppcli) ));
1585                         return False;
1586                 }
1587
1588                 /* Try again... */
1589                 cli_shutdown(*ppcli);
1590
1591                 *ppcli = cli_initialise();
1592                 if (!*ppcli) {
1593                         /* Out of memory... */
1594                         return False;
1595                 }
1596
1597                 if (!cli_connect(*ppcli, desthost, pdest_ip) ||
1598                                 !cli_session_request(*ppcli, &calling, &smbservername)) {
1599                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1600 name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
1601                         return False;
1602                 }
1603         }
1604
1605         return True;
1606 }
1607
1608
1609
1610
1611
1612 /****************************************************************************
1613  Send an old style tcon.
1614 ****************************************************************************/
1615 NTSTATUS cli_raw_tcon(struct cli_state *cli, 
1616                       const char *service, const char *pass, const char *dev,
1617                       uint16 *max_xmit, uint16 *tid)
1618 {
1619         char *p;
1620
1621         if (!lp_client_plaintext_auth() && (*pass)) {
1622                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1623                           " is disabled\n"));
1624                 return NT_STATUS_ACCESS_DENIED;
1625         }
1626
1627         memset(cli->outbuf,'\0',smb_size);
1628         memset(cli->inbuf,'\0',smb_size);
1629
1630         set_message(cli->outbuf, 0, 0, True);
1631         SCVAL(cli->outbuf,smb_com,SMBtcon);
1632         cli_setup_packet(cli);
1633
1634         p = smb_buf(cli->outbuf);
1635         *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
1636         *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
1637         *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
1638
1639         cli_setup_bcc(cli, p);
1640
1641         cli_send_smb(cli);
1642         if (!cli_receive_smb(cli)) {
1643                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1644         }
1645
1646         if (cli_is_error(cli)) {
1647                 return cli_nt_error(cli);
1648         }
1649
1650         *max_xmit = SVAL(cli->inbuf, smb_vwv0);
1651         *tid = SVAL(cli->inbuf, smb_vwv1);
1652
1653         return NT_STATUS_OK;
1654 }
1655
1656 /* Return a cli_state pointing at the IPC$ share for the given server */
1657
1658 struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
1659                                          struct user_auth_info *user_info)
1660 {
1661         struct cli_state *cli;
1662         pstring myname;
1663         NTSTATUS nt_status;
1664
1665         get_myname(myname);
1666         
1667         nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC", 
1668                                         user_info->username, lp_workgroup(), user_info->password, 
1669                                         CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, Undefined, NULL);
1670
1671         if (NT_STATUS_IS_OK(nt_status)) {
1672                 return cli;
1673         } else if (is_ipaddress(server)) {
1674             /* windows 9* needs a correct NMB name for connections */
1675             fstring remote_name;
1676
1677             if (name_status_find("*", 0, 0, *server_ip, remote_name)) {
1678                 cli = get_ipc_connect(remote_name, server_ip, user_info);
1679                 if (cli)
1680                     return cli;
1681             }
1682         }
1683         return NULL;
1684 }
1685
1686 /*
1687  * Given the IP address of a master browser on the network, return its
1688  * workgroup and connect to it.
1689  *
1690  * This function is provided to allow additional processing beyond what
1691  * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
1692  * browsers and obtain each master browsers' list of domains (in case the
1693  * first master browser is recently on the network and has not yet
1694  * synchronized with other master browsers and therefore does not yet have the
1695  * entire network browse list)
1696  */
1697
1698 struct cli_state *get_ipc_connect_master_ip(struct ip_service * mb_ip, pstring workgroup, struct user_auth_info *user_info)
1699 {
1700         static fstring name;
1701         struct cli_state *cli;
1702         struct in_addr server_ip; 
1703
1704         DEBUG(99, ("Looking up name of master browser %s\n",
1705                    inet_ntoa(mb_ip->ip)));
1706
1707         /*
1708          * Do a name status query to find out the name of the master browser.
1709          * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
1710          * master browser will not respond to a wildcard query (or, at least,
1711          * an NT4 server acting as the domain master browser will not).
1712          *
1713          * We might be able to use ONLY the query on MSBROWSE, but that's not
1714          * yet been tested with all Windows versions, so until it is, leave
1715          * the original wildcard query as the first choice and fall back to
1716          * MSBROWSE if the wildcard query fails.
1717          */
1718         if (!name_status_find("*", 0, 0x1d, mb_ip->ip, name) &&
1719             !name_status_find(MSBROWSE, 1, 0x1d, mb_ip->ip, name)) {
1720
1721                 DEBUG(99, ("Could not retrieve name status for %s\n",
1722                            inet_ntoa(mb_ip->ip)));
1723                 return NULL;
1724         }
1725
1726         if (!find_master_ip(name, &server_ip)) {
1727                 DEBUG(99, ("Could not find master ip for %s\n", name));
1728                 return NULL;
1729         }
1730
1731                 pstrcpy(workgroup, name);
1732
1733                 DEBUG(4, ("found master browser %s, %s\n", 
1734                   name, inet_ntoa(mb_ip->ip)));
1735
1736                 cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
1737
1738                 return cli;
1739     
1740 }
1741
1742 /*
1743  * Return the IP address and workgroup of a master browser on the network, and
1744  * connect to it.
1745  */
1746
1747 struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
1748 {
1749         struct ip_service *ip_list;
1750         struct cli_state *cli;
1751         int i, count;
1752
1753         DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
1754
1755         /* Go looking for workgroups by broadcasting on the local network */ 
1756
1757         if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
1758                 DEBUG(99, ("No master browsers responded\n"));
1759                 return False;
1760         }
1761
1762         for (i = 0; i < count; i++) {
1763             DEBUG(99, ("Found master browser %s\n", inet_ntoa(ip_list[i].ip)));
1764
1765             cli = get_ipc_connect_master_ip(&ip_list[i], workgroup, user_info);
1766             if (cli)
1767                     return(cli);
1768         }
1769
1770         return NULL;
1771 }