ebe19b51433e3104019cd33982a790a240e318c4
[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 Barteltt 2001-2002
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, int 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, -1, 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
192         set_message(cli->outbuf,13,0,True);
193         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
194         cli_setup_packet(cli);
195                         
196         SCVAL(cli->outbuf,smb_vwv0,0xFF);
197         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
198         SSVAL(cli->outbuf,smb_vwv3,2);
199         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
200         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
201         SSVAL(cli->outbuf,smb_vwv8,0);
202         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
203         p = smb_buf(cli->outbuf);
204         p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
205         SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
206         p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
207         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
208         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
209         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
210         cli_setup_bcc(cli, p);
211
212         cli_send_smb(cli);
213         if (!cli_receive_smb(cli))
214               return False;
215         
216         show_msg(cli->inbuf);
217         
218         if (cli_is_error(cli))
219                 return False;
220
221         cli->vuid = SVAL(cli->inbuf,smb_uid);
222         p = smb_buf(cli->inbuf);
223         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
224         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
225         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
226         fstrcpy(cli->user_name, user);
227
228         return True;
229 }
230
231 static void set_signing_on_cli (struct cli_state *cli, const char* pass, uint8 response[24]) 
232 {
233         uint8 zero_sig[8];
234         ZERO_STRUCT(zero_sig);
235
236         DEBUG(5, ("Server returned security sig:\n"));
237         dump_data(5, &cli->inbuf[smb_ss_field], 8);
238
239         if (cli->sign_info.use_smb_signing) {
240                 DEBUG(5, ("smb signing already active on connection\n"));
241         } else if (memcmp(&cli->inbuf[smb_ss_field], zero_sig, 8) != 0) {
242
243                 DEBUG(3, ("smb signing enabled!\n"));
244                 cli->sign_info.use_smb_signing = True;
245                 cli_calculate_mac_key(cli, pass, response);
246         } else {
247                 DEBUG(5, ("smb signing NOT enabled!\n"));
248         }
249 }
250
251 static void set_temp_signing_on_cli(struct cli_state *cli) 
252 {
253         if (cli->sign_info.negotiated_smb_signing)
254                 cli->sign_info.temp_smb_signing = True;
255 }
256
257
258 /****************************************************************************
259    do a NT1 NTLM/LM encrypted session setup
260    @param cli client state to create do session setup on
261    @param user username
262    @param pass *either* cleartext password (passlen !=24) or LM response.
263    @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
264    @param workgroup The user's domain.
265 ****************************************************************************/
266
267 static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, 
268                                   const char *pass, int passlen,
269                                   const char *ntpass, int ntpasslen,
270                                   const char *workgroup)
271 {
272         uint32 capabilities = cli_session_setup_capabilities(cli);
273         uchar pword[24];
274         uchar ntpword[24];
275         char *p;
276         BOOL have_plaintext = False;
277
278         if (passlen > sizeof(pword) || ntpasslen > sizeof(ntpword))
279                 return False;
280
281         if (passlen != 24) {
282                 /* non encrypted password supplied. Ignore ntpass. */
283                 passlen = 24;
284                 ntpasslen = 24;
285                 SMBencrypt(pass,cli->secblob.data,pword);
286                 SMBNTencrypt(pass,cli->secblob.data,ntpword);
287
288                 have_plaintext = True;
289                 set_temp_signing_on_cli(cli);
290         } else {
291                 /* pre-encrypted password supplied.  Only used for 
292                    security=server, can't do
293                    signing becouse we don't have oringial key */
294                 memcpy(pword, pass, 24);
295                 if (ntpasslen == 24)
296                         memcpy(ntpword, ntpass, 24);
297                 else
298                         ZERO_STRUCT(ntpword);
299         }
300
301         /* send a session setup command */
302         memset(cli->outbuf,'\0',smb_size);
303
304         set_message(cli->outbuf,13,0,True);
305         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
306         cli_setup_packet(cli);
307                         
308         SCVAL(cli->outbuf,smb_vwv0,0xFF);
309         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
310         SSVAL(cli->outbuf,smb_vwv3,2);
311         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
312         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
313         SSVAL(cli->outbuf,smb_vwv7,passlen);
314         SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
315         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
316         p = smb_buf(cli->outbuf);
317         memcpy(p,pword,passlen); p += passlen;
318         memcpy(p,ntpword,ntpasslen); p += ntpasslen;
319         p += clistr_push(cli, p, user, -1, STR_TERMINATE);
320         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE);
321         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
322         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
323         cli_setup_bcc(cli, p);
324
325         if (!cli_send_smb(cli))
326                 return False;
327
328         if (!cli_receive_smb(cli))
329                 return False;
330
331         show_msg(cli->inbuf);
332
333         if (cli_is_error(cli))
334                 return False;
335
336         /* use the returned vuid from now on */
337         cli->vuid = SVAL(cli->inbuf,smb_uid);
338         
339         p = smb_buf(cli->inbuf);
340         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
341         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
342         p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
343
344         fstrcpy(cli->user_name, user);
345
346         if (have_plaintext) {
347                 /* Have plaintext orginal */
348                 set_signing_on_cli(cli, pass, ntpword);
349         }
350         
351         return True;
352 }
353
354 /****************************************************************************
355  Send a extended security session setup blob, returning a reply blob.
356 ****************************************************************************/
357
358 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
359 {
360         uint32 capabilities = cli_session_setup_capabilities(cli);
361         char *p;
362         DATA_BLOB blob2;
363         uint32 len;
364
365         blob2 = data_blob(NULL, 0);
366
367         capabilities |= CAP_EXTENDED_SECURITY;
368
369         /* send a session setup command */
370         memset(cli->outbuf,'\0',smb_size);
371
372         set_message(cli->outbuf,12,0,True);
373         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
374
375         set_temp_signing_on_cli(cli);
376
377         cli_setup_packet(cli);
378                         
379         SCVAL(cli->outbuf,smb_vwv0,0xFF);
380         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
381         SSVAL(cli->outbuf,smb_vwv3,2);
382         SSVAL(cli->outbuf,smb_vwv4,1);
383         SIVAL(cli->outbuf,smb_vwv5,0);
384         SSVAL(cli->outbuf,smb_vwv7,blob.length);
385         SIVAL(cli->outbuf,smb_vwv10,capabilities); 
386         p = smb_buf(cli->outbuf);
387         memcpy(p, blob.data, blob.length);
388         p += blob.length;
389         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
390         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
391         cli_setup_bcc(cli, p);
392         cli_send_smb(cli);
393
394         if (!cli_receive_smb(cli))
395                 return blob2;
396
397         show_msg(cli->inbuf);
398
399         if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
400                                                   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
401                 return blob2;
402         }
403         
404         /* use the returned vuid from now on */
405         cli->vuid = SVAL(cli->inbuf,smb_uid);
406         
407         p = smb_buf(cli->inbuf);
408
409         blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
410
411         p += blob2.length;
412         p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
413
414         /* w2k with kerberos doesn't properly null terminate this field */
415         len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
416         p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
417
418         return blob2;
419 }
420
421 #ifdef HAVE_KRB5
422 /****************************************************************************
423  Do a spnego/kerberos encrypted session setup.
424 ****************************************************************************/
425
426 static BOOL cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
427 {
428         DATA_BLOB blob2, negTokenTarg;
429
430         DEBUG(2,("Doing kerberos session setup\n"));
431
432         /* generate the encapsulated kerberos5 ticket */
433         negTokenTarg = spnego_gen_negTokenTarg(principal, 0);
434
435         if (!negTokenTarg.data) return False;
436
437 #if 0
438         file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
439 #endif
440
441         blob2 = cli_session_setup_blob(cli, negTokenTarg);
442
443         /* we don't need this blob for kerberos */
444         data_blob_free(&blob2);
445
446         data_blob_free(&negTokenTarg);
447
448         return !cli_is_error(cli);
449 }
450 #endif
451
452 /****************************************************************************
453  Do a spnego/NTLMSSP encrypted session setup.
454 ****************************************************************************/
455
456 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, 
457                                       const char *pass, const char *workgroup)
458 {
459         DATA_BLOB msg1, struct_blob;
460         DATA_BLOB blob, chal1, chal2, auth, challenge_blob;
461         uint8 challenge[8];
462         uint8 nthash[24], lmhash[24], sess_key[16];
463         uint32 neg_flags, chal_flags, ntlmssp_command, unkn1, unkn2;
464         pstring server_domain;  /* FIX THIS, SHOULD be UCS2-LE */
465
466         neg_flags = NTLMSSP_NEGOTIATE_UNICODE | 
467                 NTLMSSP_NEGOTIATE_128 | 
468                 NTLMSSP_NEGOTIATE_NTLM |
469                 NTLMSSP_REQUEST_TARGET;
470
471         memset(sess_key, 0, 16);
472
473         DEBUG(10, ("sending NTLMSSP_NEGOTIATE\n"));
474
475         /* generate the ntlmssp negotiate packet */
476         msrpc_gen(&blob, "CddAA",
477                   "NTLMSSP",
478                   NTLMSSP_NEGOTIATE,
479                   neg_flags,
480                   workgroup, 
481                   cli->calling.name);
482         DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n",
483                   neg_flags, workgroup, cli->calling.name));
484         /* and wrap it in a SPNEGO wrapper */
485         msg1 = gen_negTokenInit(OID_NTLMSSP, blob);
486         data_blob_free(&blob);
487
488         /* now send that blob on its way */
489         blob = cli_session_setup_blob(cli, msg1);
490
491         data_blob_free(&msg1);
492
493         if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED))
494                 return False;
495
496 #if 0
497         file_save("chal.dat", blob.data, blob.length);
498 #endif
499
500         /* the server gives us back two challenges */
501         if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
502                 DEBUG(3,("Failed to parse challenges\n"));
503                 return False;
504         }
505
506         data_blob_free(&blob);
507
508         /*
509          * Ok, chal1 and chal2 are actually two identical copies of
510          * the NTLMSSP Challenge BLOB, and they contain, encoded in them
511          * the challenge to use.
512          */
513
514         if (!msrpc_parse(&chal1, "CdUdbddB",
515                          "NTLMSSP",
516                          &ntlmssp_command, 
517                          &server_domain,
518                          &chal_flags,
519                          &challenge_blob, 8,
520                          &unkn1, &unkn2,
521                          &struct_blob)) {
522           DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
523           return False;
524         }
525                         
526         if (ntlmssp_command != NTLMSSP_CHALLENGE) {
527                 DEBUG(0, ("NTLMSSP Response != NTLMSSP_CHALLENGE. Got %0X\n", 
528                         ntlmssp_command));
529                 return False;
530         }
531  
532         DEBUG(10, ("Challenge:\n"));
533         dump_data(10, challenge_blob.data, 8);
534
535         /* encrypt the password with the challenge which is in the blob */
536         memcpy(challenge, challenge_blob.data, 8); 
537         SMBencrypt(pass, challenge,lmhash);
538         SMBNTencrypt(pass, challenge,nthash);
539         data_blob_free(&challenge_blob);
540
541 #if 0
542         file_save("nthash.dat", nthash, 24);
543         file_save("lmhash.dat", lmhash, 24);
544         file_save("chal1.dat", chal1.data, chal1.length);
545 #endif
546
547         data_blob_free(&chal1);
548         data_blob_free(&chal2);
549
550         /* this generates the actual auth packet */
551         msrpc_gen(&blob, "CdBBUUUBd", 
552                   "NTLMSSP", 
553                   NTLMSSP_AUTH, 
554                   lmhash, 24,
555                   nthash, 24,
556                   workgroup, 
557                   user, 
558                   cli->calling.name,
559                   sess_key, 0,
560                   neg_flags);
561
562         /* wrap it in SPNEGO */
563         auth = spnego_gen_auth(blob);
564
565         data_blob_free(&blob);
566
567         /* now send the auth packet and we should be done */
568         blob = cli_session_setup_blob(cli, auth);
569
570         data_blob_free(&auth);
571         data_blob_free(&blob);
572
573         if (cli_is_error(cli))
574                 return False;
575
576         return True;
577 }
578
579 /****************************************************************************
580  Do a spnego encrypted session setup.
581 ****************************************************************************/
582
583 static BOOL cli_session_setup_spnego(struct cli_state *cli, const char *user, 
584                                      const char *pass, const char *workgroup)
585 {
586         char *principal;
587         char *OIDs[ASN1_MAX_OIDS];
588         int i;
589         BOOL got_kerberos_mechanism = False;
590         DATA_BLOB blob;
591
592         DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
593
594         /* the server might not even do spnego */
595         if (cli->secblob.length <= 16) {
596                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
597                 goto ntlmssp;
598         }
599
600 #if 0
601         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
602 #endif
603
604         /* there is 16 bytes of GUID before the real spnego packet starts */
605         blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
606
607         /* the server sent us the first part of the SPNEGO exchange in the negprot 
608            reply */
609         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
610                 data_blob_free(&blob);
611                 return False;
612         }
613         data_blob_free(&blob);
614
615         /* make sure the server understands kerberos */
616         for (i=0;OIDs[i];i++) {
617                 DEBUG(3,("got OID=%s\n", OIDs[i]));
618                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
619                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
620                         got_kerberos_mechanism = True;
621                 }
622                 free(OIDs[i]);
623         }
624         DEBUG(3,("got principal=%s\n", principal));
625
626         fstrcpy(cli->user_name, user);
627
628 #ifdef HAVE_KRB5
629         if (got_kerberos_mechanism && cli->use_kerberos) {
630                 return cli_session_setup_kerberos(cli, principal, workgroup);
631         }
632 #endif
633
634         free(principal);
635
636 ntlmssp:
637
638         return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
639 }
640
641 /****************************************************************************
642  Send a session setup. The username and workgroup is in UNIX character
643  format and must be converted to DOS codepage format before sending. If the
644  password is in plaintext, the same should be done.
645 ****************************************************************************/
646
647 BOOL cli_session_setup(struct cli_state *cli, 
648                        const char *user, 
649                        const char *pass, int passlen,
650                        const char *ntpass, int ntpasslen,
651                        const char *workgroup)
652 {
653         char *p;
654         fstring user2;
655
656         /* allow for workgroups as part of the username */
657         fstrcpy(user2, user);
658         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
659             (p=strchr_m(user2,*lp_winbind_separator()))) {
660                 *p = 0;
661                 user = p+1;
662                 workgroup = user2;
663         }
664
665         if (cli->protocol < PROTOCOL_LANMAN1)
666                 return True;
667
668         /* now work out what sort of session setup we are going to
669            do. I have split this into separate functions to make the
670            flow a bit easier to understand (tridge) */
671
672         /* if its an older server then we have to use the older request format */
673
674         if (cli->protocol < PROTOCOL_NT1)
675                 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
676
677         /* if no user is supplied then we have to do an anonymous connection.
678            passwords are ignored */
679
680         if (!user || !*user)
681                 return cli_session_setup_guest(cli);
682
683         /* if the server is share level then send a plaintext null
684            password at this point. The password is sent in the tree
685            connect */
686
687         if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
688                 return cli_session_setup_plaintext(cli, user, "", workgroup);
689
690         /* if the server doesn't support encryption then we have to use 
691            plaintext. The second password is ignored */
692
693         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0)
694                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
695
696         /* Indidicate signing */
697         
698         /* if the server supports extended security then use SPNEGO */
699
700         if (cli->capabilities & CAP_EXTENDED_SECURITY)
701                 return cli_session_setup_spnego(cli, user, pass, workgroup);
702
703         /* otherwise do a NT1 style session setup */
704
705         return cli_session_setup_nt1(cli, user, 
706                                      pass, passlen, ntpass, ntpasslen,
707                                      workgroup);        
708 }
709
710 /****************************************************************************
711  Send a uloggoff.
712 *****************************************************************************/
713
714 BOOL cli_ulogoff(struct cli_state *cli)
715 {
716         memset(cli->outbuf,'\0',smb_size);
717         set_message(cli->outbuf,2,0,True);
718         SCVAL(cli->outbuf,smb_com,SMBulogoffX);
719         cli_setup_packet(cli);
720         SSVAL(cli->outbuf,smb_vwv0,0xFF);
721         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
722
723         cli_send_smb(cli);
724         if (!cli_receive_smb(cli))
725                 return False;
726
727         return !cli_is_error(cli);
728 }
729
730 /****************************************************************************
731  Send a tconX.
732 ****************************************************************************/
733
734 BOOL cli_send_tconX(struct cli_state *cli, 
735                     const char *share, const char *dev, const char *pass, int passlen)
736 {
737         fstring fullshare, pword;
738         char *p;
739         memset(cli->outbuf,'\0',smb_size);
740         memset(cli->inbuf,'\0',smb_size);
741
742         fstrcpy(cli->share, share);
743
744         /* in user level security don't send a password now */
745         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
746                 passlen = 1;
747                 pass = "";
748         }
749
750         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
751                 /*
752                  * Non-encrypted passwords - convert to DOS codepage before encryption.
753                  */
754                 passlen = 24;
755                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
756         } else {
757                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
758                         /*
759                          * Non-encrypted passwords - convert to DOS codepage before using.
760                          */
761                         passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
762                 } else {
763                         memcpy(pword, pass, passlen);
764                 }
765         }
766
767         if (cli->port == 445) {
768                 slprintf(fullshare, sizeof(fullshare)-1,
769                          "%s", share);
770         } else {
771                 slprintf(fullshare, sizeof(fullshare)-1,
772                          "\\\\%s\\%s", cli->desthost, share);
773         }
774
775         set_message(cli->outbuf,4, 0, True);
776         SCVAL(cli->outbuf,smb_com,SMBtconX);
777         cli_setup_packet(cli);
778
779         SSVAL(cli->outbuf,smb_vwv0,0xFF);
780         SSVAL(cli->outbuf,smb_vwv3,passlen);
781
782         p = smb_buf(cli->outbuf);
783         memcpy(p,pword,passlen);
784         p += passlen;
785         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
786         fstrcpy(p, dev); p += strlen(dev)+1;
787
788         cli_setup_bcc(cli, p);
789
790         cli_send_smb(cli);
791         if (!cli_receive_smb(cli))
792                 return False;
793
794         if (cli_is_error(cli))
795                 return False;
796
797         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
798
799         if (strcasecmp(share,"IPC$")==0)
800                 fstrcpy(cli->dev, "IPC");
801
802         if (cli->protocol >= PROTOCOL_NT1 &&
803             smb_buflen(cli->inbuf) == 3) {
804                 /* almost certainly win95 - enable bug fixes */
805                 cli->win95 = True;
806         }
807
808         cli->cnum = SVAL(cli->inbuf,smb_tid);
809         return True;
810 }
811
812 /****************************************************************************
813  Send a tree disconnect.
814 ****************************************************************************/
815
816 BOOL cli_tdis(struct cli_state *cli)
817 {
818         memset(cli->outbuf,'\0',smb_size);
819         set_message(cli->outbuf,0,0,True);
820         SCVAL(cli->outbuf,smb_com,SMBtdis);
821         SSVAL(cli->outbuf,smb_tid,cli->cnum);
822         cli_setup_packet(cli);
823         
824         cli_send_smb(cli);
825         if (!cli_receive_smb(cli))
826                 return False;
827         
828         return !cli_is_error(cli);
829 }
830
831 /****************************************************************************
832  Send a negprot command.
833 ****************************************************************************/
834
835 void cli_negprot_send(struct cli_state *cli)
836 {
837         char *p;
838         int numprots;
839
840         if (cli->protocol < PROTOCOL_NT1)
841                 cli->use_spnego = False;
842
843         memset(cli->outbuf,'\0',smb_size);
844
845         /* setup the protocol strings */
846         set_message(cli->outbuf,0,0,True);
847
848         p = smb_buf(cli->outbuf);
849         for (numprots=0;
850              prots[numprots].name && prots[numprots].prot<=cli->protocol;
851              numprots++) {
852                 *p++ = 2;
853                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
854         }
855
856         SCVAL(cli->outbuf,smb_com,SMBnegprot);
857         cli_setup_bcc(cli, p);
858         cli_setup_packet(cli);
859
860         SCVAL(smb_buf(cli->outbuf),0,2);
861
862         cli_send_smb(cli);
863 }
864
865 /****************************************************************************
866  Send a negprot command.
867 ****************************************************************************/
868
869 BOOL cli_negprot(struct cli_state *cli)
870 {
871         char *p;
872         int numprots;
873         int plength;
874
875         if (cli->sign_info.use_smb_signing) {
876                 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
877                 return False;
878         }
879
880         if (cli->protocol < PROTOCOL_NT1)
881                 cli->use_spnego = False;
882
883         memset(cli->outbuf,'\0',smb_size);
884
885         /* setup the protocol strings */
886         for (plength=0,numprots=0;
887              prots[numprots].name && prots[numprots].prot<=cli->protocol;
888              numprots++)
889                 plength += strlen(prots[numprots].name)+2;
890     
891         set_message(cli->outbuf,0,plength,True);
892
893         p = smb_buf(cli->outbuf);
894         for (numprots=0;
895              prots[numprots].name && prots[numprots].prot<=cli->protocol;
896              numprots++) {
897                 *p++ = 2;
898                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
899         }
900
901         SCVAL(cli->outbuf,smb_com,SMBnegprot);
902         cli_setup_packet(cli);
903
904         SCVAL(smb_buf(cli->outbuf),0,2);
905
906         cli_send_smb(cli);
907         if (!cli_receive_smb(cli))
908                 return False;
909
910         show_msg(cli->inbuf);
911
912         if (cli_is_error(cli) ||
913             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
914                 return(False);
915         }
916
917         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
918
919         if (cli->protocol >= PROTOCOL_NT1) {    
920                 /* NT protocol */
921                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
922                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
923                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
924                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
925                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
926                 cli->serverzone *= 60;
927                 /* this time arrives in real GMT */
928                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
929                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
930                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
931                 if (cli->capabilities & CAP_RAW_MODE) {
932                         cli->readbraw_supported = True;
933                         cli->writebraw_supported = True;      
934                 }
935                 /* work out if they sent us a workgroup */
936                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
937                     smb_buflen(cli->inbuf) > 8) {
938                         clistr_pull(cli, cli->server_domain, 
939                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
940                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
941                 }
942
943                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED))
944                         cli->sign_info.negotiated_smb_signing = True;
945
946                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && cli->sign_info.allow_smb_signing)
947                         cli->sign_info.negotiated_smb_signing = True;
948
949         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
950                 cli->use_spnego = False;
951                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
952                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
953                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
954                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
955                 cli->serverzone *= 60;
956                 /* this time is converted to GMT by make_unix_date */
957                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
958                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
959                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
960                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
961         } else {
962                 /* the old core protocol */
963                 cli->use_spnego = False;
964                 cli->sec_mode = 0;
965                 cli->serverzone = TimeDiff(time(NULL));
966         }
967
968         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
969
970         /* a way to force ascii SMB */
971         if (getenv("CLI_FORCE_ASCII"))
972                 cli->capabilities &= ~CAP_UNICODE;
973
974         return True;
975 }
976
977 /****************************************************************************
978  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
979 ****************************************************************************/
980
981 BOOL cli_session_request(struct cli_state *cli,
982                          struct nmb_name *calling, struct nmb_name *called)
983 {
984         char *p;
985         int len = 4;
986         extern pstring user_socket_options;
987
988         memcpy(&(cli->calling), calling, sizeof(*calling));
989         memcpy(&(cli->called ), called , sizeof(*called ));
990   
991         /* put in the destination name */
992         p = cli->outbuf+len;
993         name_mangle(cli->called .name, p, cli->called .name_type);
994         len += name_len(p);
995
996         /* and my name */
997         p = cli->outbuf+len;
998         name_mangle(cli->calling.name, p, cli->calling.name_type);
999         len += name_len(p);
1000
1001         /* 445 doesn't have session request */
1002         if (cli->port == 445)
1003                 return True;
1004
1005         if (cli->sign_info.use_smb_signing) {
1006                 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
1007                 return False;
1008         }
1009
1010         /* send a session request (RFC 1002) */
1011         /* setup the packet length
1012          * Remove four bytes from the length count, since the length
1013          * field in the NBT Session Service header counts the number
1014          * of bytes which follow.  The cli_send_smb() function knows
1015          * about this and accounts for those four bytes.
1016          * CRH.
1017          */
1018         len -= 4;
1019         _smb_setlen(cli->outbuf,len);
1020         SCVAL(cli->outbuf,0,0x81);
1021
1022         cli_send_smb(cli);
1023         DEBUG(5,("Sent session request\n"));
1024
1025         if (!cli_receive_smb(cli))
1026                 return False;
1027
1028         if (CVAL(cli->inbuf,0) == 0x84) {
1029                 /* C. Hoch  9/14/95 Start */
1030                 /* For information, here is the response structure.
1031                  * We do the byte-twiddling to for portability.
1032                 struct RetargetResponse{
1033                 unsigned char type;
1034                 unsigned char flags;
1035                 int16 length;
1036                 int32 ip_addr;
1037                 int16 port;
1038                 };
1039                 */
1040                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1041                 /* SESSION RETARGET */
1042                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1043
1044                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1045                 if (cli->fd == -1)
1046                         return False;
1047
1048                 DEBUG(3,("Retargeted\n"));
1049
1050                 set_socket_options(cli->fd,user_socket_options);
1051
1052                 /* Try again */
1053                 {
1054                         static int depth;
1055                         BOOL ret;
1056                         if (depth > 4) {
1057                                 DEBUG(0,("Retarget recursion - failing\n"));
1058                                 return False;
1059                         }
1060                         depth++;
1061                         ret = cli_session_request(cli, calling, called);
1062                         depth--;
1063                         return ret;
1064                 }
1065         } /* C. Hoch 9/14/95 End */
1066
1067         if (CVAL(cli->inbuf,0) != 0x82) {
1068                 /* This is the wrong place to put the error... JRA. */
1069                 cli->rap_error = CVAL(cli->inbuf,4);
1070                 return False;
1071         }
1072         return(True);
1073 }
1074
1075 /****************************************************************************
1076  Open the client sockets.
1077 ****************************************************************************/
1078
1079 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1080 {
1081         extern pstring user_socket_options;
1082         int name_type = 0x20;
1083         char *p;
1084
1085         /* reasonable default hostname */
1086         if (!host) host = "*SMBSERVER";
1087
1088         fstrcpy(cli->desthost, host);
1089
1090         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1091         if ((p = strchr(cli->desthost, '#'))) {
1092                 name_type = strtol(p+1, NULL, 16);              
1093                 *p = 0;
1094         }
1095         
1096         if (!ip || is_zero_ip(*ip)) {
1097                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1098                         return False;
1099                 }
1100                 if (ip) *ip = cli->dest_ip;
1101         } else {
1102                 cli->dest_ip = *ip;
1103         }
1104
1105         if (getenv("LIBSMB_PROG")) {
1106                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1107         } else {
1108                 /* try 445 first, then 139 */
1109                 int port = cli->port?cli->port:445;
1110                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1111                                           port, cli->timeout);
1112                 if (cli->fd == -1 && cli->port == 0) {
1113                         port = 139;
1114                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1115                                                   port, cli->timeout);
1116                 }
1117                 if (cli->fd != -1)
1118                         cli->port = port;
1119         }
1120         if (cli->fd == -1) {
1121                 DEBUG(1,("Error connecting to %s (%s)\n",
1122                          ip?inet_ntoa(*ip):host,strerror(errno)));
1123                 return False;
1124         }
1125
1126         set_socket_options(cli->fd,user_socket_options);
1127
1128         return True;
1129 }
1130
1131 /****************************************************************************
1132  Initialise client credentials for authenticated pipe access.
1133 ****************************************************************************/
1134
1135 static void init_creds(struct ntuser_creds *creds, const char* username,
1136                        const char* domain, const char* password)
1137 {
1138         ZERO_STRUCTP(creds);
1139
1140         pwd_set_cleartext(&creds->pwd, password);
1141
1142         fstrcpy(creds->user_name, username);
1143         fstrcpy(creds->domain, domain);
1144
1145         if (!*username) {
1146                 creds->pwd.null_pwd = True;
1147         }
1148 }
1149
1150 /**
1151    establishes a connection right up to doing tconX, password specified.
1152    @param output_cli A fully initialised cli structure, non-null only on success
1153    @param dest_host The netbios name of the remote host
1154    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1155    @param port (optional) The destination port (0 for default)
1156    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1157    @param service_type The 'type' of serivice. 
1158    @param user Username, unix string
1159    @param domain User's domain
1160    @param password User's password, unencrypted unix string.
1161    @param retry BOOL. Did this connection fail with a retryable error ?
1162 */
1163
1164 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1165                              const char *my_name, 
1166                              const char *dest_host, 
1167                              struct in_addr *dest_ip, int port,
1168                              const char *service, const char *service_type,
1169                              const char *user, const char *domain, 
1170                              const char *password, int flags,
1171                              BOOL *retry) 
1172 {
1173         struct ntuser_creds creds;
1174         NTSTATUS nt_status;
1175         struct nmb_name calling;
1176         struct nmb_name called;
1177         struct cli_state *cli;
1178         struct in_addr ip;
1179
1180         if (retry)
1181                 *retry = False;
1182
1183         if (!my_name) 
1184                 my_name = global_myname();
1185         
1186         if (!(cli = cli_initialise(NULL)))
1187                 return NT_STATUS_NO_MEMORY;
1188         
1189         make_nmb_name(&calling, my_name, 0x0);
1190         make_nmb_name(&called , dest_host, 0x20);
1191
1192         if (cli_set_port(cli, port) != port) {
1193                 cli_shutdown(cli);
1194                 return NT_STATUS_UNSUCCESSFUL;
1195         }
1196
1197         cli_set_timeout(cli, 10000); /* 10 seconds. */
1198
1199         if (dest_ip)
1200                 ip = *dest_ip;
1201         else
1202                 ZERO_STRUCT(ip);
1203
1204 again:
1205
1206         DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1207         
1208         if (!cli_connect(cli, dest_host, &ip)) {
1209                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1210                          nmb_namestr(&called), inet_ntoa(ip)));
1211                 cli_shutdown(cli);
1212                 return NT_STATUS_UNSUCCESSFUL;
1213         }
1214
1215         if (retry)
1216                 *retry = True;
1217
1218         if (!cli_session_request(cli, &calling, &called)) {
1219                 char *p;
1220                 DEBUG(1,("session request to %s failed (%s)\n", 
1221                          called.name, cli_errstr(cli)));
1222                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1223                         *p = 0;
1224                         goto again;
1225                 }
1226                 if (strcmp(called.name, "*SMBSERVER")) {
1227                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1228                         goto again;
1229                 }
1230                 return NT_STATUS_UNSUCCESSFUL;
1231         }
1232
1233         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1234                 cli->use_spnego = False;
1235         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1236                 cli->use_kerberos = True;
1237
1238         if (!cli_negprot(cli)) {
1239                 DEBUG(1,("failed negprot\n"));
1240                 nt_status = NT_STATUS_UNSUCCESSFUL;
1241                 cli_shutdown(cli);
1242                 return nt_status;
1243         }
1244
1245         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1246                                password, strlen(password)+1, 
1247                                domain)) {
1248                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1249                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1250                 } else {
1251                         nt_status = cli_nt_error(cli);
1252                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1253                         cli_shutdown(cli);
1254                         if (NT_STATUS_IS_OK(nt_status)) 
1255                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1256                         return nt_status;
1257                 }
1258         } 
1259
1260         if (service) {
1261                 if (!cli_send_tconX(cli, service, service_type,
1262                                     password, strlen(password)+1)) {
1263                         nt_status = cli_nt_error(cli);
1264                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1265                         cli_shutdown(cli);
1266                         if (NT_STATUS_IS_OK(nt_status)) {
1267                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1268                         }
1269                         return nt_status;
1270                 }
1271         }
1272
1273         init_creds(&creds, user, domain, password);
1274         cli_init_creds(cli, &creds);
1275
1276         *output_cli = cli;
1277         return NT_STATUS_OK;
1278 }
1279
1280 /****************************************************************************
1281  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1282 ****************************************************************************/
1283
1284 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1285                                      struct in_addr *pdest_ip)
1286 {
1287         struct nmb_name calling, called;
1288
1289         make_nmb_name(&calling, srchost, 0x0);
1290
1291         /*
1292          * If the called name is an IP address
1293          * then use *SMBSERVER immediately.
1294          */
1295
1296         if(is_ipaddress(desthost))
1297                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1298         else
1299                 make_nmb_name(&called, desthost, 0x20);
1300
1301         if (!cli_session_request(cli, &calling, &called)) {
1302                 struct nmb_name smbservername;
1303
1304                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1305
1306                 /*
1307                  * If the name wasn't *SMBSERVER then
1308                  * try with *SMBSERVER if the first name fails.
1309                  */
1310
1311                 if (nmb_name_equal(&called, &smbservername)) {
1312
1313                         /*
1314                          * The name used was *SMBSERVER, don't bother with another name.
1315                          */
1316
1317                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1318 with error %s.\n", desthost, cli_errstr(cli) ));
1319                         return False;
1320                 }
1321
1322                 /*
1323                  * We need to close the connection here but can't call cli_shutdown as
1324                  * will free an allocated cli struct. cli_close_connection was invented
1325                  * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1326                  */
1327
1328                 cli_close_connection(cli);
1329
1330                 if (!cli_initialise(cli) ||
1331                                 !cli_connect(cli, desthost, pdest_ip) ||
1332                                 !cli_session_request(cli, &calling, &smbservername)) {
1333                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1334 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1335                         return False;
1336                 }
1337         }
1338
1339         return True;
1340 }