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