Refactor signing code to remove most dependencies on 'struct cli'.
[samba.git] / source3 / libsmb / cliconnect.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client connect/disconnect routines
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Andrew Bartlett 2001-2003
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #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         snprintf( lanman, sizeof(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 static void use_in_memory_ccache(void) {
476         setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
477 }
478
479 /****************************************************************************
480  Do a spnego/kerberos encrypted session setup.
481 ****************************************************************************/
482
483 static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
484 {
485         DATA_BLOB blob2, negTokenTarg;
486
487         DEBUG(2,("Doing kerberos session setup\n"));
488
489         /* generate the encapsulated kerberos5 ticket */
490         negTokenTarg = spnego_gen_negTokenTarg(principal, 0);
491
492         if (!negTokenTarg.data) return False;
493
494 #if 0
495         file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
496 #endif
497
498         blob2 = cli_session_setup_blob(cli, negTokenTarg);
499
500         /* we don't need this blob for kerberos */
501         data_blob_free(&blob2);
502
503         data_blob_free(&negTokenTarg);
504
505         return !cli_is_error(cli);
506 }
507 #endif  /* HAVE_KRB5 */
508
509
510 /****************************************************************************
511  Do a spnego/NTLMSSP encrypted session setup.
512 ****************************************************************************/
513
514 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, 
515                                       const char *pass, const char *workgroup)
516 {
517         struct ntlmssp_client_state *ntlmssp_state;
518         NTSTATUS nt_status;
519         int turn = 1;
520         DATA_BLOB msg1;
521         DATA_BLOB blob;
522         DATA_BLOB blob_in = data_blob(NULL, 0);
523         DATA_BLOB blob_out;
524
525         cli_temp_set_signing(cli);
526
527         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
528                 return False;
529         }
530
531         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
532                 return False;
533         }
534         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, workgroup))) {
535                 return False;
536         }
537         if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
538                 return False;
539         }
540
541         ntlmssp_state->use_ntlmv2 = lp_client_ntlmv2_auth();
542
543         if (cli->sign_info.negotiated_smb_signing 
544             || cli->sign_info.mandatory_signing) {
545                 ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN;
546                 ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
547         }
548
549         do {
550                 nt_status = ntlmssp_client_update(ntlmssp_state, 
551                                                   blob_in, &blob_out);
552                 data_blob_free(&blob_in);
553                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
554                         DATA_BLOB null = data_blob(NULL, 0);
555                         if (turn == 1) {
556                                 /* and wrap it in a SPNEGO wrapper */
557                                 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
558                         } else {
559                                 /* wrap it in SPNEGO */
560                                 msg1 = spnego_gen_auth(blob_out);
561                         }
562                 
563                         cli_simple_set_signing(cli, 
564                                                ntlmssp_state->session_key.data, 
565                                                null); 
566                         
567                         /* now send that blob on its way */
568                         if (!cli_session_setup_blob_send(cli, msg1)) {
569                                 return False;
570                         }
571                         data_blob_free(&msg1);
572                         
573                         blob = cli_session_setup_blob_receive(cli);
574
575                         nt_status = cli_nt_error(cli);
576                 }
577                 
578                 if (!blob.length) {
579                         if (NT_STATUS_IS_OK(nt_status)) {
580                                 nt_status = NT_STATUS_UNSUCCESSFUL;
581                         }
582                 } else if ((turn == 1) && 
583                            NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
584                         DATA_BLOB tmp_blob = data_blob(NULL, 0);
585                         /* the server might give us back two challenges */
586                         if (!spnego_parse_challenge(blob, &blob_in, 
587                                                     &tmp_blob)) {
588                                 DEBUG(3,("Failed to parse challenges\n"));
589                                 nt_status = NT_STATUS_INVALID_PARAMETER;
590                         }
591                         data_blob_free(&tmp_blob);
592                 } else {
593                         if (!spnego_parse_auth_response(blob, nt_status, 
594                                                         &blob_in)) {
595                                 DEBUG(3,("Failed to parse auth response\n"));
596                                 if (NT_STATUS_IS_OK(nt_status) 
597                                     || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) 
598                                         nt_status = NT_STATUS_INVALID_PARAMETER;
599                         }
600                 }
601                 data_blob_free(&blob);
602                 data_blob_free(&blob_out);
603                 turn++;
604         } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
605
606         if (NT_STATUS_IS_OK(nt_status)) {
607                 set_cli_session_key(cli, ntlmssp_state->session_key);
608         }
609
610         /* we have a reference conter on ntlmssp_state, if we are signing
611            then the state will be kept by the signing engine */
612
613         if (!NT_STATUS_IS_OK(ntlmssp_client_end(&ntlmssp_state))) {
614                 return False;
615         }
616
617         return (NT_STATUS_IS_OK(nt_status));
618 }
619
620 /****************************************************************************
621  Do a spnego encrypted session setup.
622 ****************************************************************************/
623
624 static BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user, 
625                                      const char *pass, const char *workgroup)
626 {
627         char *principal;
628         char *OIDs[ASN1_MAX_OIDS];
629         int i;
630         BOOL got_kerberos_mechanism = False;
631         DATA_BLOB blob;
632
633         DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
634
635         /* the server might not even do spnego */
636         if (cli->secblob.length <= 16) {
637                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
638                 goto ntlmssp;
639         }
640
641 #if 0
642         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
643 #endif
644
645         /* there is 16 bytes of GUID before the real spnego packet starts */
646         blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
647
648         /* the server sent us the first part of the SPNEGO exchange in the negprot 
649            reply */
650         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
651                 data_blob_free(&blob);
652                 return False;
653         }
654         data_blob_free(&blob);
655
656         /* make sure the server understands kerberos */
657         for (i=0;OIDs[i];i++) {
658                 DEBUG(3,("got OID=%s\n", OIDs[i]));
659                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
660                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
661                         got_kerberos_mechanism = True;
662                 }
663                 free(OIDs[i]);
664         }
665         DEBUG(3,("got principal=%s\n", principal));
666
667         fstrcpy(cli->user_name, user);
668
669 #ifdef HAVE_KRB5
670         /* If password is set we reauthenticate to kerberos server
671          * and do not store results */
672
673         if (got_kerberos_mechanism && cli->use_kerberos) {
674                 if (*pass) {
675                         int ret;
676                         
677                         use_in_memory_ccache();
678                         ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */);
679                         
680                         if (ret){
681                                 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
682                                 return False;
683                         }
684                 }
685                 
686                 return cli_session_setup_kerberos(cli, principal, workgroup);
687         }
688 #endif
689
690         free(principal);
691
692 ntlmssp:
693
694         return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
695 }
696
697 /****************************************************************************
698  Send a session setup. The username and workgroup is in UNIX character
699  format and must be converted to DOS codepage format before sending. If the
700  password is in plaintext, the same should be done.
701 ****************************************************************************/
702
703 BOOL cli_session_setup(struct cli_state *cli, 
704                        const char *user, 
705                        const char *pass, int passlen,
706                        const char *ntpass, int ntpasslen,
707                        const char *workgroup)
708 {
709         char *p;
710         fstring user2;
711
712         /* allow for workgroups as part of the username */
713         fstrcpy(user2, user);
714         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
715             (p=strchr_m(user2,*lp_winbind_separator()))) {
716                 *p = 0;
717                 user = p+1;
718                 workgroup = user2;
719         }
720
721         if (cli->protocol < PROTOCOL_LANMAN1)
722                 return True;
723
724         /* now work out what sort of session setup we are going to
725            do. I have split this into separate functions to make the
726            flow a bit easier to understand (tridge) */
727
728         /* if its an older server then we have to use the older request format */
729
730         if (cli->protocol < PROTOCOL_NT1) {
731                 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
732                         DEBUG(1, ("Server requested LM password but 'client lanman auth'"
733                                   " is disabled\n"));
734                         return False;
735                 }
736
737                 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
738                     !lp_client_plaintext_auth() && (*pass)) {
739                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
740                                   " is disabled\n"));
741                         return False;
742                 }
743
744                 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
745         }
746
747         /* if no user is supplied then we have to do an anonymous connection.
748            passwords are ignored */
749
750         if (!user || !*user)
751                 return cli_session_setup_guest(cli);
752
753         /* if the server is share level then send a plaintext null
754            password at this point. The password is sent in the tree
755            connect */
756
757         if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) 
758                 return cli_session_setup_plaintext(cli, user, "", workgroup);
759
760         /* if the server doesn't support encryption then we have to use 
761            plaintext. The second password is ignored */
762
763         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
764                 if (!lp_client_plaintext_auth() && (*pass)) {
765                         DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
766                                   " is disabled\n"));
767                         return False;
768                 }
769                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
770         }
771
772         /* if the server supports extended security then use SPNEGO */
773
774         if (cli->capabilities & CAP_EXTENDED_SECURITY)
775                 return cli_session_setup_spnego(cli, user, pass, workgroup);
776
777         /* otherwise do a NT1 style session setup */
778
779         return cli_session_setup_nt1(cli, user, 
780                                      pass, passlen, ntpass, ntpasslen,
781                                      workgroup);        
782 }
783
784 /****************************************************************************
785  Send a uloggoff.
786 *****************************************************************************/
787
788 BOOL cli_ulogoff(struct cli_state *cli)
789 {
790         memset(cli->outbuf,'\0',smb_size);
791         set_message(cli->outbuf,2,0,True);
792         SCVAL(cli->outbuf,smb_com,SMBulogoffX);
793         cli_setup_packet(cli);
794         SSVAL(cli->outbuf,smb_vwv0,0xFF);
795         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
796
797         cli_send_smb(cli);
798         if (!cli_receive_smb(cli))
799                 return False;
800
801         return !cli_is_error(cli);
802 }
803
804 /****************************************************************************
805  Send a tconX.
806 ****************************************************************************/
807 BOOL cli_send_tconX(struct cli_state *cli, 
808                     const char *share, const char *dev, const char *pass, int passlen)
809 {
810         fstring fullshare, pword;
811         char *p;
812         memset(cli->outbuf,'\0',smb_size);
813         memset(cli->inbuf,'\0',smb_size);
814
815         fstrcpy(cli->share, share);
816
817         /* in user level security don't send a password now */
818         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
819                 passlen = 1;
820                 pass = "";
821         }
822
823         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
824                 if (!lp_client_lanman_auth()) {
825                         DEBUG(1, ("Server requested LANMAN password but 'client use lanman auth'"
826                                   " is disabled\n"));
827                         return False;
828                 }
829
830                 /*
831                  * Non-encrypted passwords - convert to DOS codepage before encryption.
832                  */
833                 passlen = 24;
834                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
835         } else {
836                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
837                         if (!lp_client_plaintext_auth() && (*pass)) {
838                                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
839                                           " is disabled\n"));
840                                 return False;
841                         }
842
843                         /*
844                          * Non-encrypted passwords - convert to DOS codepage before using.
845                          */
846                         passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
847                         
848                 } else {
849                         memcpy(pword, pass, passlen);
850                 }
851         }
852
853         slprintf(fullshare, sizeof(fullshare)-1,
854                  "\\\\%s\\%s", cli->desthost, share);
855
856         set_message(cli->outbuf,4, 0, True);
857         SCVAL(cli->outbuf,smb_com,SMBtconX);
858         cli_setup_packet(cli);
859
860         SSVAL(cli->outbuf,smb_vwv0,0xFF);
861         SSVAL(cli->outbuf,smb_vwv3,passlen);
862
863         p = smb_buf(cli->outbuf);
864         memcpy(p,pword,passlen);
865         p += passlen;
866         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
867         fstrcpy(p, dev); p += strlen(dev)+1;
868
869         cli_setup_bcc(cli, p);
870
871         cli_send_smb(cli);
872         if (!cli_receive_smb(cli))
873                 return False;
874
875         if (cli_is_error(cli))
876                 return False;
877
878         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
879
880         if (cli->protocol >= PROTOCOL_NT1 &&
881             smb_buflen(cli->inbuf) == 3) {
882                 /* almost certainly win95 - enable bug fixes */
883                 cli->win95 = True;
884         }
885
886         cli->cnum = SVAL(cli->inbuf,smb_tid);
887         return True;
888 }
889
890 /****************************************************************************
891  Send a tree disconnect.
892 ****************************************************************************/
893
894 BOOL cli_tdis(struct cli_state *cli)
895 {
896         memset(cli->outbuf,'\0',smb_size);
897         set_message(cli->outbuf,0,0,True);
898         SCVAL(cli->outbuf,smb_com,SMBtdis);
899         SSVAL(cli->outbuf,smb_tid,cli->cnum);
900         cli_setup_packet(cli);
901         
902         cli_send_smb(cli);
903         if (!cli_receive_smb(cli))
904                 return False;
905         
906         return !cli_is_error(cli);
907 }
908
909 /****************************************************************************
910  Send a negprot command.
911 ****************************************************************************/
912
913 void cli_negprot_send(struct cli_state *cli)
914 {
915         char *p;
916         int numprots;
917
918         if (cli->protocol < PROTOCOL_NT1)
919                 cli->use_spnego = False;
920
921         memset(cli->outbuf,'\0',smb_size);
922
923         /* setup the protocol strings */
924         set_message(cli->outbuf,0,0,True);
925
926         p = smb_buf(cli->outbuf);
927         for (numprots=0;
928              prots[numprots].name && prots[numprots].prot<=cli->protocol;
929              numprots++) {
930                 *p++ = 2;
931                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
932         }
933
934         SCVAL(cli->outbuf,smb_com,SMBnegprot);
935         cli_setup_bcc(cli, p);
936         cli_setup_packet(cli);
937
938         SCVAL(smb_buf(cli->outbuf),0,2);
939
940         cli_send_smb(cli);
941 }
942
943 /****************************************************************************
944  Send a negprot command.
945 ****************************************************************************/
946
947 BOOL cli_negprot(struct cli_state *cli)
948 {
949         char *p;
950         int numprots;
951         int plength;
952
953         if (cli->protocol < PROTOCOL_NT1)
954                 cli->use_spnego = False;
955
956         memset(cli->outbuf,'\0',smb_size);
957
958         /* setup the protocol strings */
959         for (plength=0,numprots=0;
960              prots[numprots].name && prots[numprots].prot<=cli->protocol;
961              numprots++)
962                 plength += strlen(prots[numprots].name)+2;
963     
964         set_message(cli->outbuf,0,plength,True);
965
966         p = smb_buf(cli->outbuf);
967         for (numprots=0;
968              prots[numprots].name && prots[numprots].prot<=cli->protocol;
969              numprots++) {
970                 *p++ = 2;
971                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
972         }
973
974         SCVAL(cli->outbuf,smb_com,SMBnegprot);
975         cli_setup_packet(cli);
976
977         SCVAL(smb_buf(cli->outbuf),0,2);
978
979         cli_send_smb(cli);
980         if (!cli_receive_smb(cli))
981                 return False;
982
983         show_msg(cli->inbuf);
984
985         if (cli_is_error(cli) ||
986             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
987                 return(False);
988         }
989
990         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
991
992         if ((cli->protocol < PROTOCOL_NT1) && (lp_client_signing() == Required)) {
993                 DEBUG(1,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
994                 return False;
995         }
996
997         if (cli->protocol >= PROTOCOL_NT1) {    
998                 /* NT protocol */
999                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
1000                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
1001                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
1002                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
1003                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
1004                 cli->serverzone *= 60;
1005                 /* this time arrives in real GMT */
1006                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1007                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1008                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1009                 if (cli->capabilities & CAP_RAW_MODE) {
1010                         cli->readbraw_supported = True;
1011                         cli->writebraw_supported = True;      
1012                 }
1013                 /* work out if they sent us a workgroup */
1014                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1015                     smb_buflen(cli->inbuf) > 8) {
1016                         clistr_pull(cli, cli->server_domain, 
1017                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
1018                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
1019                 }
1020
1021                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)) {
1022                         /* Fail if signing is mandatory and we don't want to support it. */
1023                         if (!lp_client_signing()) {
1024                                 DEBUG(1,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1025                                 return False;
1026                         }
1027                         cli->sign_info.negotiated_smb_signing = True;
1028                 }
1029
1030                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && cli->sign_info.allow_smb_signing)
1031                         cli->sign_info.negotiated_smb_signing = True;
1032
1033                 /* Fail if signing is mandatory and the server doesn't support it. */
1034                 if (cli->sign_info.mandatory_signing && !(cli->sign_info.negotiated_smb_signing)) {
1035                         DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1036                         return False;
1037                 }
1038
1039         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1040                 cli->use_spnego = False;
1041                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
1042                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
1043                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
1044                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
1045                 cli->serverzone *= 60;
1046                 /* this time is converted to GMT by make_unix_date */
1047                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
1048                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
1049                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
1050                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1051         } else {
1052                 /* the old core protocol */
1053                 cli->use_spnego = False;
1054                 cli->sec_mode = 0;
1055                 cli->serverzone = TimeDiff(time(NULL));
1056         }
1057
1058         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1059
1060         /* a way to force ascii SMB */
1061         if (getenv("CLI_FORCE_ASCII"))
1062                 cli->capabilities &= ~CAP_UNICODE;
1063
1064         return True;
1065 }
1066
1067 /****************************************************************************
1068  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1069 ****************************************************************************/
1070
1071 BOOL cli_session_request(struct cli_state *cli,
1072                          struct nmb_name *calling, struct nmb_name *called)
1073 {
1074         char *p;
1075         int len = 4;
1076         extern pstring user_socket_options;
1077
1078         memcpy(&(cli->calling), calling, sizeof(*calling));
1079         memcpy(&(cli->called ), called , sizeof(*called ));
1080   
1081         /* put in the destination name */
1082         p = cli->outbuf+len;
1083         name_mangle(cli->called .name, p, cli->called .name_type);
1084         len += name_len(p);
1085
1086         /* and my name */
1087         p = cli->outbuf+len;
1088         name_mangle(cli->calling.name, p, cli->calling.name_type);
1089         len += name_len(p);
1090
1091         /* 445 doesn't have session request */
1092         if (cli->port == 445)
1093                 return True;
1094
1095         /* send a session request (RFC 1002) */
1096         /* setup the packet length
1097          * Remove four bytes from the length count, since the length
1098          * field in the NBT Session Service header counts the number
1099          * of bytes which follow.  The cli_send_smb() function knows
1100          * about this and accounts for those four bytes.
1101          * CRH.
1102          */
1103         len -= 4;
1104         _smb_setlen(cli->outbuf,len);
1105         SCVAL(cli->outbuf,0,0x81);
1106
1107         cli_send_smb(cli);
1108         DEBUG(5,("Sent session request\n"));
1109
1110         if (!cli_receive_smb(cli))
1111                 return False;
1112
1113         if (CVAL(cli->inbuf,0) == 0x84) {
1114                 /* C. Hoch  9/14/95 Start */
1115                 /* For information, here is the response structure.
1116                  * We do the byte-twiddling to for portability.
1117                 struct RetargetResponse{
1118                 unsigned char type;
1119                 unsigned char flags;
1120                 int16 length;
1121                 int32 ip_addr;
1122                 int16 port;
1123                 };
1124                 */
1125                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1126                 /* SESSION RETARGET */
1127                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1128
1129                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1130                 if (cli->fd == -1)
1131                         return False;
1132
1133                 DEBUG(3,("Retargeted\n"));
1134
1135                 set_socket_options(cli->fd,user_socket_options);
1136
1137                 /* Try again */
1138                 {
1139                         static int depth;
1140                         BOOL ret;
1141                         if (depth > 4) {
1142                                 DEBUG(0,("Retarget recursion - failing\n"));
1143                                 return False;
1144                         }
1145                         depth++;
1146                         ret = cli_session_request(cli, calling, called);
1147                         depth--;
1148                         return ret;
1149                 }
1150         } /* C. Hoch 9/14/95 End */
1151
1152         if (CVAL(cli->inbuf,0) != 0x82) {
1153                 /* This is the wrong place to put the error... JRA. */
1154                 cli->rap_error = CVAL(cli->inbuf,4);
1155                 return False;
1156         }
1157         return(True);
1158 }
1159
1160 /****************************************************************************
1161  Open the client sockets.
1162 ****************************************************************************/
1163
1164 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1165 {
1166         extern pstring user_socket_options;
1167         int name_type = 0x20;
1168         char *p;
1169
1170         /* reasonable default hostname */
1171         if (!host) host = "*SMBSERVER";
1172
1173         fstrcpy(cli->desthost, host);
1174
1175         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1176         if ((p = strchr(cli->desthost, '#'))) {
1177                 name_type = strtol(p+1, NULL, 16);              
1178                 *p = 0;
1179         }
1180         
1181         if (!ip || is_zero_ip(*ip)) {
1182                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1183                         return False;
1184                 }
1185                 if (ip) *ip = cli->dest_ip;
1186         } else {
1187                 cli->dest_ip = *ip;
1188         }
1189
1190         if (getenv("LIBSMB_PROG")) {
1191                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1192         } else {
1193                 /* try 445 first, then 139 */
1194                 int port = cli->port?cli->port:445;
1195                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1196                                           port, cli->timeout);
1197                 if (cli->fd == -1 && cli->port == 0) {
1198                         port = 139;
1199                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1200                                                   port, cli->timeout);
1201                 }
1202                 if (cli->fd != -1)
1203                         cli->port = port;
1204         }
1205         if (cli->fd == -1) {
1206                 DEBUG(1,("Error connecting to %s (%s)\n",
1207                          ip?inet_ntoa(*ip):host,strerror(errno)));
1208                 return False;
1209         }
1210
1211         set_socket_options(cli->fd,user_socket_options);
1212
1213         return True;
1214 }
1215
1216 /****************************************************************************
1217  Initialise client credentials for authenticated pipe access.
1218 ****************************************************************************/
1219
1220 static void init_creds(struct ntuser_creds *creds, const char* username,
1221                        const char* domain, const char* password)
1222 {
1223         ZERO_STRUCTP(creds);
1224
1225         pwd_set_cleartext(&creds->pwd, password);
1226
1227         fstrcpy(creds->user_name, username);
1228         fstrcpy(creds->domain, domain);
1229
1230         if (!*username) {
1231                 creds->pwd.null_pwd = True;
1232         }
1233 }
1234
1235 /**
1236    establishes a connection right up to doing tconX, password specified.
1237    @param output_cli A fully initialised cli structure, non-null only on success
1238    @param dest_host The netbios name of the remote host
1239    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1240    @param port (optional) The destination port (0 for default)
1241    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1242    @param service_type The 'type' of serivice. 
1243    @param user Username, unix string
1244    @param domain User's domain
1245    @param password User's password, unencrypted unix string.
1246    @param retry BOOL. Did this connection fail with a retryable error ?
1247 */
1248
1249 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1250                              const char *my_name, 
1251                              const char *dest_host, 
1252                              struct in_addr *dest_ip, int port,
1253                              const char *service, const char *service_type,
1254                              const char *user, const char *domain, 
1255                              const char *password, int flags,
1256                              BOOL *retry) 
1257 {
1258         struct ntuser_creds creds;
1259         NTSTATUS nt_status;
1260         struct nmb_name calling;
1261         struct nmb_name called;
1262         struct cli_state *cli;
1263         struct in_addr ip;
1264
1265         if (retry)
1266                 *retry = False;
1267
1268         if (!my_name) 
1269                 my_name = global_myname();
1270         
1271         if (!(cli = cli_initialise(NULL)))
1272                 return NT_STATUS_NO_MEMORY;
1273         
1274         make_nmb_name(&calling, my_name, 0x0);
1275         make_nmb_name(&called , dest_host, 0x20);
1276
1277         if (cli_set_port(cli, port) != port) {
1278                 cli_shutdown(cli);
1279                 return NT_STATUS_UNSUCCESSFUL;
1280         }
1281
1282         cli_set_timeout(cli, 10000); /* 10 seconds. */
1283
1284         if (dest_ip)
1285                 ip = *dest_ip;
1286         else
1287                 ZERO_STRUCT(ip);
1288
1289 again:
1290
1291         DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1292         
1293         if (!cli_connect(cli, dest_host, &ip)) {
1294                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1295                          nmb_namestr(&called), inet_ntoa(ip)));
1296                 cli_shutdown(cli);
1297                 return NT_STATUS_UNSUCCESSFUL;
1298         }
1299
1300         if (retry)
1301                 *retry = True;
1302
1303         if (!cli_session_request(cli, &calling, &called)) {
1304                 char *p;
1305                 DEBUG(1,("session request to %s failed (%s)\n", 
1306                          called.name, cli_errstr(cli)));
1307                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1308                         *p = 0;
1309                         goto again;
1310                 }
1311                 if (strcmp(called.name, "*SMBSERVER")) {
1312                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1313                         goto again;
1314                 }
1315                 return NT_STATUS_UNSUCCESSFUL;
1316         }
1317
1318         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1319                 cli->use_spnego = False;
1320         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1321                 cli->use_kerberos = True;
1322
1323         if (!cli_negprot(cli)) {
1324                 DEBUG(1,("failed negprot\n"));
1325                 nt_status = NT_STATUS_UNSUCCESSFUL;
1326                 cli_shutdown(cli);
1327                 return nt_status;
1328         }
1329
1330         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1331                                password, strlen(password)+1, 
1332                                domain)) {
1333                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1334                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1335                 } else {
1336                         nt_status = cli_nt_error(cli);
1337                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1338                         cli_shutdown(cli);
1339                         if (NT_STATUS_IS_OK(nt_status)) 
1340                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1341                         return nt_status;
1342                 }
1343         } 
1344
1345         if (service) {
1346                 if (!cli_send_tconX(cli, service, service_type,
1347                                     password, strlen(password)+1)) {
1348                         nt_status = cli_nt_error(cli);
1349                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1350                         cli_shutdown(cli);
1351                         if (NT_STATUS_IS_OK(nt_status)) {
1352                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1353                         }
1354                         return nt_status;
1355                 }
1356         }
1357
1358         init_creds(&creds, user, domain, password);
1359         cli_init_creds(cli, &creds);
1360
1361         *output_cli = cli;
1362         return NT_STATUS_OK;
1363 }
1364
1365 /****************************************************************************
1366  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1367 ****************************************************************************/
1368
1369 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1370                                      struct in_addr *pdest_ip)
1371 {
1372         struct nmb_name calling, called;
1373
1374         make_nmb_name(&calling, srchost, 0x0);
1375
1376         /*
1377          * If the called name is an IP address
1378          * then use *SMBSERVER immediately.
1379          */
1380
1381         if(is_ipaddress(desthost))
1382                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1383         else
1384                 make_nmb_name(&called, desthost, 0x20);
1385
1386         if (!cli_session_request(cli, &calling, &called)) {
1387                 struct nmb_name smbservername;
1388
1389                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1390
1391                 /*
1392                  * If the name wasn't *SMBSERVER then
1393                  * try with *SMBSERVER if the first name fails.
1394                  */
1395
1396                 if (nmb_name_equal(&called, &smbservername)) {
1397
1398                         /*
1399                          * The name used was *SMBSERVER, don't bother with another name.
1400                          */
1401
1402                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1403 with error %s.\n", desthost, cli_errstr(cli) ));
1404                         return False;
1405                 }
1406
1407                 /*
1408                  * We need to close the connection here but can't call cli_shutdown as
1409                  * will free an allocated cli struct. cli_close_connection was invented
1410                  * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1411                  */
1412
1413                 cli_close_connection(cli);
1414
1415                 if (!cli_initialise(cli) ||
1416                                 !cli_connect(cli, desthost, pdest_ip) ||
1417                                 !cli_session_request(cli, &calling, &smbservername)) {
1418                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1419 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1420                         return False;
1421                 }
1422         }
1423
1424         return True;
1425 }
1426
1427
1428
1429
1430
1431 /****************************************************************************
1432  Send an old style tcon.
1433 ****************************************************************************/
1434 NTSTATUS cli_raw_tcon(struct cli_state *cli, 
1435                       const char *service, const char *pass, const char *dev,
1436                       uint16 *max_xmit, uint16 *tid)
1437 {
1438         char *p;
1439
1440         if (!lp_client_plaintext_auth() && (*pass)) {
1441                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1442                           " is disabled\n"));
1443                 return NT_STATUS_ACCESS_DENIED;
1444         }
1445
1446         memset(cli->outbuf,'\0',smb_size);
1447         memset(cli->inbuf,'\0',smb_size);
1448
1449         set_message(cli->outbuf, 0, 0, True);
1450         SCVAL(cli->outbuf,smb_com,SMBtcon);
1451         cli_setup_packet(cli);
1452
1453         p = smb_buf(cli->outbuf);
1454         *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
1455         *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
1456         *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
1457
1458         cli_setup_bcc(cli, p);
1459
1460         cli_send_smb(cli);
1461         if (!cli_receive_smb(cli)) {
1462                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1463         }
1464
1465         if (cli_is_error(cli)) {
1466                 return cli_nt_error(cli);
1467         }
1468
1469         *max_xmit = SVAL(cli->inbuf, smb_vwv0);
1470         *tid = SVAL(cli->inbuf, smb_vwv1);
1471
1472         return NT_STATUS_OK;
1473 }
1474
1475 /* Return a cli_state pointing at the IPC$ share for the given server */
1476
1477 struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
1478                                          struct user_auth_info *user_info)
1479 {
1480         struct cli_state *cli;
1481         pstring myname;
1482         NTSTATUS nt_status;
1483
1484         get_myname(myname);
1485         
1486         nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC", 
1487                                         user_info->username, lp_workgroup(), user_info->password, 
1488                                         CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, NULL);
1489
1490         if (NT_STATUS_IS_OK(nt_status)) {
1491                 return cli;
1492         } else if (is_ipaddress(server)) {
1493             /* windows 9* needs a correct NMB name for connections */
1494             fstring remote_name;
1495
1496             if (name_status_find("*", 0, 0, *server_ip, remote_name)) {
1497                 cli = get_ipc_connect(remote_name, server_ip, user_info);
1498                 if (cli)
1499                     return cli;
1500             }
1501         }
1502         return NULL;
1503 }
1504
1505 /* Return the IP address and workgroup of a master browser on the 
1506    network. */
1507
1508 struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
1509 {
1510         struct ip_service *ip_list;
1511         struct cli_state *cli;
1512         int i, count;
1513         struct in_addr server_ip; 
1514
1515         /* Go looking for workgroups by broadcasting on the local network */ 
1516
1517         if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
1518                 return False;
1519         }
1520
1521         for (i = 0; i < count; i++) {
1522                 static fstring name;
1523
1524                 if (!name_status_find("*", 0, 0x1d, ip_list[i].ip, name))
1525                         continue;
1526
1527                 if (!find_master_ip(name, &server_ip))
1528                         continue;
1529
1530                 pstrcpy(workgroup, name);
1531
1532                 DEBUG(4, ("found master browser %s, %s\n", 
1533                           name, inet_ntoa(ip_list[i].ip)));
1534
1535                 cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
1536
1537                 if (!cli)
1538                     continue;
1539                 
1540                 return cli;
1541         }
1542
1543         return NULL;
1544 }