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