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