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