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