Spelling.
[gd/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) {    
993                 /* NT protocol */
994                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
995                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
996                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
997                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
998                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
999                 cli->serverzone *= 60;
1000                 /* this time arrives in real GMT */
1001                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1002                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1003                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1004                 if (cli->capabilities & CAP_RAW_MODE) {
1005                         cli->readbraw_supported = True;
1006                         cli->writebraw_supported = True;      
1007                 }
1008                 /* work out if they sent us a workgroup */
1009                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1010                     smb_buflen(cli->inbuf) > 8) {
1011                         clistr_pull(cli, cli->server_domain, 
1012                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
1013                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
1014                 }
1015
1016                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED)) {
1017                         /* Fail if signing is mandatory and we don't want to support it. */
1018                         if (!lp_client_signing()) {
1019                                 DEBUG(1,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1020                                 return False;
1021                         }
1022                         cli->sign_info.negotiated_smb_signing = True;
1023                 }
1024
1025                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && cli->sign_info.allow_smb_signing)
1026                         cli->sign_info.negotiated_smb_signing = True;
1027
1028                 /* Fail if signing is mandatory and the server doesn't support it. */
1029                 if (cli->sign_info.mandatory_signing && !(cli->sign_info.negotiated_smb_signing)) {
1030                         DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1031                         return False;
1032                 }
1033
1034         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1035                 cli->use_spnego = False;
1036                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
1037                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
1038                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
1039                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
1040                 cli->serverzone *= 60;
1041                 /* this time is converted to GMT by make_unix_date */
1042                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
1043                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
1044                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
1045                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1046         } else {
1047                 /* the old core protocol */
1048                 cli->use_spnego = False;
1049                 cli->sec_mode = 0;
1050                 cli->serverzone = TimeDiff(time(NULL));
1051         }
1052
1053         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1054
1055         /* a way to force ascii SMB */
1056         if (getenv("CLI_FORCE_ASCII"))
1057                 cli->capabilities &= ~CAP_UNICODE;
1058
1059         return True;
1060 }
1061
1062 /****************************************************************************
1063  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1064 ****************************************************************************/
1065
1066 BOOL cli_session_request(struct cli_state *cli,
1067                          struct nmb_name *calling, struct nmb_name *called)
1068 {
1069         char *p;
1070         int len = 4;
1071         extern pstring user_socket_options;
1072
1073         memcpy(&(cli->calling), calling, sizeof(*calling));
1074         memcpy(&(cli->called ), called , sizeof(*called ));
1075   
1076         /* put in the destination name */
1077         p = cli->outbuf+len;
1078         name_mangle(cli->called .name, p, cli->called .name_type);
1079         len += name_len(p);
1080
1081         /* and my name */
1082         p = cli->outbuf+len;
1083         name_mangle(cli->calling.name, p, cli->calling.name_type);
1084         len += name_len(p);
1085
1086         /* 445 doesn't have session request */
1087         if (cli->port == 445)
1088                 return True;
1089
1090         /* send a session request (RFC 1002) */
1091         /* setup the packet length
1092          * Remove four bytes from the length count, since the length
1093          * field in the NBT Session Service header counts the number
1094          * of bytes which follow.  The cli_send_smb() function knows
1095          * about this and accounts for those four bytes.
1096          * CRH.
1097          */
1098         len -= 4;
1099         _smb_setlen(cli->outbuf,len);
1100         SCVAL(cli->outbuf,0,0x81);
1101
1102         cli_send_smb(cli);
1103         DEBUG(5,("Sent session request\n"));
1104
1105         if (!cli_receive_smb(cli))
1106                 return False;
1107
1108         if (CVAL(cli->inbuf,0) == 0x84) {
1109                 /* C. Hoch  9/14/95 Start */
1110                 /* For information, here is the response structure.
1111                  * We do the byte-twiddling to for portability.
1112                 struct RetargetResponse{
1113                 unsigned char type;
1114                 unsigned char flags;
1115                 int16 length;
1116                 int32 ip_addr;
1117                 int16 port;
1118                 };
1119                 */
1120                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1121                 /* SESSION RETARGET */
1122                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1123
1124                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1125                 if (cli->fd == -1)
1126                         return False;
1127
1128                 DEBUG(3,("Retargeted\n"));
1129
1130                 set_socket_options(cli->fd,user_socket_options);
1131
1132                 /* Try again */
1133                 {
1134                         static int depth;
1135                         BOOL ret;
1136                         if (depth > 4) {
1137                                 DEBUG(0,("Retarget recursion - failing\n"));
1138                                 return False;
1139                         }
1140                         depth++;
1141                         ret = cli_session_request(cli, calling, called);
1142                         depth--;
1143                         return ret;
1144                 }
1145         } /* C. Hoch 9/14/95 End */
1146
1147         if (CVAL(cli->inbuf,0) != 0x82) {
1148                 /* This is the wrong place to put the error... JRA. */
1149                 cli->rap_error = CVAL(cli->inbuf,4);
1150                 return False;
1151         }
1152         return(True);
1153 }
1154
1155 /****************************************************************************
1156  Open the client sockets.
1157 ****************************************************************************/
1158
1159 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1160 {
1161         extern pstring user_socket_options;
1162         int name_type = 0x20;
1163         char *p;
1164
1165         /* reasonable default hostname */
1166         if (!host) host = "*SMBSERVER";
1167
1168         fstrcpy(cli->desthost, host);
1169
1170         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1171         if ((p = strchr(cli->desthost, '#'))) {
1172                 name_type = strtol(p+1, NULL, 16);              
1173                 *p = 0;
1174         }
1175         
1176         if (!ip || is_zero_ip(*ip)) {
1177                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1178                         return False;
1179                 }
1180                 if (ip) *ip = cli->dest_ip;
1181         } else {
1182                 cli->dest_ip = *ip;
1183         }
1184
1185         if (getenv("LIBSMB_PROG")) {
1186                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1187         } else {
1188                 /* try 445 first, then 139 */
1189                 int port = cli->port?cli->port:445;
1190                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1191                                           port, cli->timeout);
1192                 if (cli->fd == -1 && cli->port == 0) {
1193                         port = 139;
1194                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1195                                                   port, cli->timeout);
1196                 }
1197                 if (cli->fd != -1)
1198                         cli->port = port;
1199         }
1200         if (cli->fd == -1) {
1201                 DEBUG(1,("Error connecting to %s (%s)\n",
1202                          ip?inet_ntoa(*ip):host,strerror(errno)));
1203                 return False;
1204         }
1205
1206         set_socket_options(cli->fd,user_socket_options);
1207
1208         return True;
1209 }
1210
1211 /****************************************************************************
1212  Initialise client credentials for authenticated pipe access.
1213 ****************************************************************************/
1214
1215 static void init_creds(struct ntuser_creds *creds, const char* username,
1216                        const char* domain, const char* password)
1217 {
1218         ZERO_STRUCTP(creds);
1219
1220         pwd_set_cleartext(&creds->pwd, password);
1221
1222         fstrcpy(creds->user_name, username);
1223         fstrcpy(creds->domain, domain);
1224
1225         if (!*username) {
1226                 creds->pwd.null_pwd = True;
1227         }
1228 }
1229
1230 /**
1231    establishes a connection right up to doing tconX, password specified.
1232    @param output_cli A fully initialised cli structure, non-null only on success
1233    @param dest_host The netbios name of the remote host
1234    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1235    @param port (optional) The destination port (0 for default)
1236    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1237    @param service_type The 'type' of serivice. 
1238    @param user Username, unix string
1239    @param domain User's domain
1240    @param password User's password, unencrypted unix string.
1241    @param retry BOOL. Did this connection fail with a retryable error ?
1242 */
1243
1244 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1245                              const char *my_name, 
1246                              const char *dest_host, 
1247                              struct in_addr *dest_ip, int port,
1248                              const char *service, const char *service_type,
1249                              const char *user, const char *domain, 
1250                              const char *password, int flags,
1251                              BOOL *retry) 
1252 {
1253         struct ntuser_creds creds;
1254         NTSTATUS nt_status;
1255         struct nmb_name calling;
1256         struct nmb_name called;
1257         struct cli_state *cli;
1258         struct in_addr ip;
1259
1260         if (retry)
1261                 *retry = False;
1262
1263         if (!my_name) 
1264                 my_name = global_myname();
1265         
1266         if (!(cli = cli_initialise(NULL)))
1267                 return NT_STATUS_NO_MEMORY;
1268         
1269         make_nmb_name(&calling, my_name, 0x0);
1270         make_nmb_name(&called , dest_host, 0x20);
1271
1272         if (cli_set_port(cli, port) != port) {
1273                 cli_shutdown(cli);
1274                 return NT_STATUS_UNSUCCESSFUL;
1275         }
1276
1277         cli_set_timeout(cli, 10000); /* 10 seconds. */
1278
1279         if (dest_ip)
1280                 ip = *dest_ip;
1281         else
1282                 ZERO_STRUCT(ip);
1283
1284 again:
1285
1286         DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1287         
1288         if (!cli_connect(cli, dest_host, &ip)) {
1289                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1290                          nmb_namestr(&called), inet_ntoa(ip)));
1291                 cli_shutdown(cli);
1292                 return NT_STATUS_UNSUCCESSFUL;
1293         }
1294
1295         if (retry)
1296                 *retry = True;
1297
1298         if (!cli_session_request(cli, &calling, &called)) {
1299                 char *p;
1300                 DEBUG(1,("session request to %s failed (%s)\n", 
1301                          called.name, cli_errstr(cli)));
1302                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1303                         *p = 0;
1304                         goto again;
1305                 }
1306                 if (strcmp(called.name, "*SMBSERVER")) {
1307                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1308                         goto again;
1309                 }
1310                 return NT_STATUS_UNSUCCESSFUL;
1311         }
1312
1313         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1314                 cli->use_spnego = False;
1315         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1316                 cli->use_kerberos = True;
1317
1318         if (!cli_negprot(cli)) {
1319                 DEBUG(1,("failed negprot\n"));
1320                 nt_status = NT_STATUS_UNSUCCESSFUL;
1321                 cli_shutdown(cli);
1322                 return nt_status;
1323         }
1324
1325         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1326                                password, strlen(password)+1, 
1327                                domain)) {
1328                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1329                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1330                 } else {
1331                         nt_status = cli_nt_error(cli);
1332                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1333                         cli_shutdown(cli);
1334                         if (NT_STATUS_IS_OK(nt_status)) 
1335                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1336                         return nt_status;
1337                 }
1338         } 
1339
1340         if (service) {
1341                 if (!cli_send_tconX(cli, service, service_type,
1342                                     password, strlen(password)+1)) {
1343                         nt_status = cli_nt_error(cli);
1344                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1345                         cli_shutdown(cli);
1346                         if (NT_STATUS_IS_OK(nt_status)) {
1347                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1348                         }
1349                         return nt_status;
1350                 }
1351         }
1352
1353         init_creds(&creds, user, domain, password);
1354         cli_init_creds(cli, &creds);
1355
1356         *output_cli = cli;
1357         return NT_STATUS_OK;
1358 }
1359
1360 /****************************************************************************
1361  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1362 ****************************************************************************/
1363
1364 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1365                                      struct in_addr *pdest_ip)
1366 {
1367         struct nmb_name calling, called;
1368
1369         make_nmb_name(&calling, srchost, 0x0);
1370
1371         /*
1372          * If the called name is an IP address
1373          * then use *SMBSERVER immediately.
1374          */
1375
1376         if(is_ipaddress(desthost))
1377                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1378         else
1379                 make_nmb_name(&called, desthost, 0x20);
1380
1381         if (!cli_session_request(cli, &calling, &called)) {
1382                 struct nmb_name smbservername;
1383
1384                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1385
1386                 /*
1387                  * If the name wasn't *SMBSERVER then
1388                  * try with *SMBSERVER if the first name fails.
1389                  */
1390
1391                 if (nmb_name_equal(&called, &smbservername)) {
1392
1393                         /*
1394                          * The name used was *SMBSERVER, don't bother with another name.
1395                          */
1396
1397                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1398 with error %s.\n", desthost, cli_errstr(cli) ));
1399                         return False;
1400                 }
1401
1402                 /*
1403                  * We need to close the connection here but can't call cli_shutdown as
1404                  * will free an allocated cli struct. cli_close_connection was invented
1405                  * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1406                  */
1407
1408                 cli_close_connection(cli);
1409
1410                 if (!cli_initialise(cli) ||
1411                                 !cli_connect(cli, desthost, pdest_ip) ||
1412                                 !cli_session_request(cli, &calling, &smbservername)) {
1413                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1414 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1415                         return False;
1416                 }
1417         }
1418
1419         return True;
1420 }
1421
1422
1423
1424
1425
1426 /****************************************************************************
1427  Send an old style tcon.
1428 ****************************************************************************/
1429 NTSTATUS cli_raw_tcon(struct cli_state *cli, 
1430                       const char *service, const char *pass, const char *dev,
1431                       uint16 *max_xmit, uint16 *tid)
1432 {
1433         char *p;
1434
1435         if (!lp_client_plaintext_auth() && (*pass)) {
1436                 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1437                           " is disabled\n"));
1438                 return NT_STATUS_ACCESS_DENIED;
1439         }
1440
1441         memset(cli->outbuf,'\0',smb_size);
1442         memset(cli->inbuf,'\0',smb_size);
1443
1444         set_message(cli->outbuf, 0, 0, True);
1445         SCVAL(cli->outbuf,smb_com,SMBtcon);
1446         cli_setup_packet(cli);
1447
1448         p = smb_buf(cli->outbuf);
1449         *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
1450         *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
1451         *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
1452
1453         cli_setup_bcc(cli, p);
1454
1455         cli_send_smb(cli);
1456         if (!cli_receive_smb(cli)) {
1457                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1458         }
1459
1460         if (cli_is_error(cli)) {
1461                 return cli_nt_error(cli);
1462         }
1463
1464         *max_xmit = SVAL(cli->inbuf, smb_vwv0);
1465         *tid = SVAL(cli->inbuf, smb_vwv1);
1466
1467         return NT_STATUS_OK;
1468 }
1469
1470 /* Return a cli_state pointing at the IPC$ share for the given server */
1471
1472 struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
1473                                          struct user_auth_info *user_info)
1474 {
1475         struct cli_state *cli;
1476         pstring myname;
1477         NTSTATUS nt_status;
1478
1479         get_myname(myname);
1480         
1481         nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC", 
1482                                         user_info->username, lp_workgroup(), user_info->password, 
1483                                         CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, NULL);
1484
1485         if (NT_STATUS_IS_OK(nt_status)) {
1486                 return cli;
1487         } else if (is_ipaddress(server)) {
1488             /* windows 9* needs a correct NMB name for connections */
1489             fstring remote_name;
1490
1491             if (name_status_find("*", 0, 0, *server_ip, remote_name)) {
1492                 cli = get_ipc_connect(remote_name, server_ip, user_info);
1493                 if (cli)
1494                     return cli;
1495             }
1496         }
1497         return NULL;
1498 }
1499
1500 /* Return the IP address and workgroup of a master browser on the 
1501    network. */
1502
1503 struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
1504 {
1505         struct ip_service *ip_list;
1506         struct cli_state *cli;
1507         int i, count;
1508         struct in_addr server_ip; 
1509
1510         /* Go looking for workgroups by broadcasting on the local network */ 
1511
1512         if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
1513                 return False;
1514         }
1515
1516         for (i = 0; i < count; i++) {
1517                 static fstring name;
1518
1519                 if (!name_status_find("*", 0, 0x1d, ip_list[i].ip, name))
1520                         continue;
1521
1522                 if (!find_master_ip(name, &server_ip))
1523                         continue;
1524
1525                 pstrcpy(workgroup, name);
1526
1527                 DEBUG(4, ("found master browser %s, %s\n", 
1528                           name, inet_ntoa(ip_list[i].ip)));
1529
1530                 cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
1531
1532                 if (!cli)
1533                     continue;
1534                 
1535                 return cli;
1536         }
1537
1538         return NULL;
1539 }