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