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