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