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