This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[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, 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 BOOL cli_send_tconX(struct cli_state *cli, 
754                     const char *share, const char *dev, const char *pass, int passlen)
755 {
756         fstring fullshare, pword;
757         char *p;
758         memset(cli->outbuf,'\0',smb_size);
759         memset(cli->inbuf,'\0',smb_size);
760
761         fstrcpy(cli->share, share);
762
763         /* in user level security don't send a password now */
764         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
765                 passlen = 1;
766                 pass = "";
767         }
768
769         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
770                 /*
771                  * Non-encrypted passwords - convert to DOS codepage before encryption.
772                  */
773                 passlen = 24;
774                 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
775         } else {
776                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
777                         /*
778                          * Non-encrypted passwords - convert to DOS codepage before using.
779                          */
780                         passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
781                 } else {
782                         memcpy(pword, pass, passlen);
783                 }
784         }
785
786         slprintf(fullshare, sizeof(fullshare)-1,
787                  "\\\\%s\\%s", cli->desthost, share);
788
789         set_message(cli->outbuf,4, 0, True);
790         SCVAL(cli->outbuf,smb_com,SMBtconX);
791         cli_setup_packet(cli);
792
793         SSVAL(cli->outbuf,smb_vwv0,0xFF);
794         SSVAL(cli->outbuf,smb_vwv3,passlen);
795
796         p = smb_buf(cli->outbuf);
797         memcpy(p,pword,passlen);
798         p += passlen;
799         p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
800         fstrcpy(p, dev); p += strlen(dev)+1;
801
802         cli_setup_bcc(cli, p);
803
804         cli_send_smb(cli);
805         if (!cli_receive_smb(cli))
806                 return False;
807
808         if (cli_is_error(cli))
809                 return False;
810
811         clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
812
813         if (cli->protocol >= PROTOCOL_NT1 &&
814             smb_buflen(cli->inbuf) == 3) {
815                 /* almost certainly win95 - enable bug fixes */
816                 cli->win95 = True;
817         }
818
819         cli->cnum = SVAL(cli->inbuf,smb_tid);
820         return True;
821 }
822
823 /****************************************************************************
824  Send a tree disconnect.
825 ****************************************************************************/
826
827 BOOL cli_tdis(struct cli_state *cli)
828 {
829         memset(cli->outbuf,'\0',smb_size);
830         set_message(cli->outbuf,0,0,True);
831         SCVAL(cli->outbuf,smb_com,SMBtdis);
832         SSVAL(cli->outbuf,smb_tid,cli->cnum);
833         cli_setup_packet(cli);
834         
835         cli_send_smb(cli);
836         if (!cli_receive_smb(cli))
837                 return False;
838         
839         return !cli_is_error(cli);
840 }
841
842 /****************************************************************************
843  Send a negprot command.
844 ****************************************************************************/
845
846 void cli_negprot_send(struct cli_state *cli)
847 {
848         char *p;
849         int numprots;
850
851         if (cli->protocol < PROTOCOL_NT1)
852                 cli->use_spnego = False;
853
854         memset(cli->outbuf,'\0',smb_size);
855
856         /* setup the protocol strings */
857         set_message(cli->outbuf,0,0,True);
858
859         p = smb_buf(cli->outbuf);
860         for (numprots=0;
861              prots[numprots].name && prots[numprots].prot<=cli->protocol;
862              numprots++) {
863                 *p++ = 2;
864                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
865         }
866
867         SCVAL(cli->outbuf,smb_com,SMBnegprot);
868         cli_setup_bcc(cli, p);
869         cli_setup_packet(cli);
870
871         SCVAL(smb_buf(cli->outbuf),0,2);
872
873         cli_send_smb(cli);
874 }
875
876 /****************************************************************************
877  Send a negprot command.
878 ****************************************************************************/
879
880 BOOL cli_negprot(struct cli_state *cli)
881 {
882         char *p;
883         int numprots;
884         int plength;
885
886         if (cli->protocol < PROTOCOL_NT1)
887                 cli->use_spnego = False;
888
889         memset(cli->outbuf,'\0',smb_size);
890
891         /* setup the protocol strings */
892         for (plength=0,numprots=0;
893              prots[numprots].name && prots[numprots].prot<=cli->protocol;
894              numprots++)
895                 plength += strlen(prots[numprots].name)+2;
896     
897         set_message(cli->outbuf,0,plength,True);
898
899         p = smb_buf(cli->outbuf);
900         for (numprots=0;
901              prots[numprots].name && prots[numprots].prot<=cli->protocol;
902              numprots++) {
903                 *p++ = 2;
904                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
905         }
906
907         SCVAL(cli->outbuf,smb_com,SMBnegprot);
908         cli_setup_packet(cli);
909
910         SCVAL(smb_buf(cli->outbuf),0,2);
911
912         cli_send_smb(cli);
913         if (!cli_receive_smb(cli))
914                 return False;
915
916         show_msg(cli->inbuf);
917
918         if (cli_is_error(cli) ||
919             ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
920                 return(False);
921         }
922
923         cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;  
924
925         if (cli->protocol >= PROTOCOL_NT1) {    
926                 /* NT protocol */
927                 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
928                 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
929                 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
930                 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
931                 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
932                 cli->serverzone *= 60;
933                 /* this time arrives in real GMT */
934                 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
935                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
936                 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
937                 if (cli->capabilities & CAP_RAW_MODE) {
938                         cli->readbraw_supported = True;
939                         cli->writebraw_supported = True;      
940                 }
941                 /* work out if they sent us a workgroup */
942                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
943                     smb_buflen(cli->inbuf) > 8) {
944                         clistr_pull(cli, cli->server_domain, 
945                                     smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
946                                     smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
947                 }
948
949                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED))
950                         cli->sign_info.negotiated_smb_signing = True;
951
952                 if ((cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && cli->sign_info.allow_smb_signing)
953                         cli->sign_info.negotiated_smb_signing = True;
954
955         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
956                 cli->use_spnego = False;
957                 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
958                 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
959                 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
960                 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
961                 cli->serverzone *= 60;
962                 /* this time is converted to GMT by make_unix_date */
963                 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
964                 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
965                 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
966                 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
967         } else {
968                 /* the old core protocol */
969                 cli->use_spnego = False;
970                 cli->sec_mode = 0;
971                 cli->serverzone = TimeDiff(time(NULL));
972         }
973
974         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
975
976         /* a way to force ascii SMB */
977         if (getenv("CLI_FORCE_ASCII"))
978                 cli->capabilities &= ~CAP_UNICODE;
979
980         return True;
981 }
982
983 /****************************************************************************
984  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
985 ****************************************************************************/
986
987 BOOL cli_session_request(struct cli_state *cli,
988                          struct nmb_name *calling, struct nmb_name *called)
989 {
990         char *p;
991         int len = 4;
992         extern pstring user_socket_options;
993
994         memcpy(&(cli->calling), calling, sizeof(*calling));
995         memcpy(&(cli->called ), called , sizeof(*called ));
996   
997         /* put in the destination name */
998         p = cli->outbuf+len;
999         name_mangle(cli->called .name, p, cli->called .name_type);
1000         len += name_len(p);
1001
1002         /* and my name */
1003         p = cli->outbuf+len;
1004         name_mangle(cli->calling.name, p, cli->calling.name_type);
1005         len += name_len(p);
1006
1007         /* 445 doesn't have session request */
1008         if (cli->port == 445)
1009                 return True;
1010
1011         /* send a session request (RFC 1002) */
1012         /* setup the packet length
1013          * Remove four bytes from the length count, since the length
1014          * field in the NBT Session Service header counts the number
1015          * of bytes which follow.  The cli_send_smb() function knows
1016          * about this and accounts for those four bytes.
1017          * CRH.
1018          */
1019         len -= 4;
1020         _smb_setlen(cli->outbuf,len);
1021         SCVAL(cli->outbuf,0,0x81);
1022
1023         cli_send_smb(cli);
1024         DEBUG(5,("Sent session request\n"));
1025
1026         if (!cli_receive_smb(cli))
1027                 return False;
1028
1029         if (CVAL(cli->inbuf,0) == 0x84) {
1030                 /* C. Hoch  9/14/95 Start */
1031                 /* For information, here is the response structure.
1032                  * We do the byte-twiddling to for portability.
1033                 struct RetargetResponse{
1034                 unsigned char type;
1035                 unsigned char flags;
1036                 int16 length;
1037                 int32 ip_addr;
1038                 int16 port;
1039                 };
1040                 */
1041                 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1042                 /* SESSION RETARGET */
1043                 putip((char *)&cli->dest_ip,cli->inbuf+4);
1044
1045                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1046                 if (cli->fd == -1)
1047                         return False;
1048
1049                 DEBUG(3,("Retargeted\n"));
1050
1051                 set_socket_options(cli->fd,user_socket_options);
1052
1053                 /* Try again */
1054                 {
1055                         static int depth;
1056                         BOOL ret;
1057                         if (depth > 4) {
1058                                 DEBUG(0,("Retarget recursion - failing\n"));
1059                                 return False;
1060                         }
1061                         depth++;
1062                         ret = cli_session_request(cli, calling, called);
1063                         depth--;
1064                         return ret;
1065                 }
1066         } /* C. Hoch 9/14/95 End */
1067
1068         if (CVAL(cli->inbuf,0) != 0x82) {
1069                 /* This is the wrong place to put the error... JRA. */
1070                 cli->rap_error = CVAL(cli->inbuf,4);
1071                 return False;
1072         }
1073         return(True);
1074 }
1075
1076 /****************************************************************************
1077  Open the client sockets.
1078 ****************************************************************************/
1079
1080 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1081 {
1082         extern pstring user_socket_options;
1083         int name_type = 0x20;
1084         char *p;
1085
1086         /* reasonable default hostname */
1087         if (!host) host = "*SMBSERVER";
1088
1089         fstrcpy(cli->desthost, host);
1090
1091         /* allow hostnames of the form NAME#xx and do a netbios lookup */
1092         if ((p = strchr(cli->desthost, '#'))) {
1093                 name_type = strtol(p+1, NULL, 16);              
1094                 *p = 0;
1095         }
1096         
1097         if (!ip || is_zero_ip(*ip)) {
1098                 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1099                         return False;
1100                 }
1101                 if (ip) *ip = cli->dest_ip;
1102         } else {
1103                 cli->dest_ip = *ip;
1104         }
1105
1106         if (getenv("LIBSMB_PROG")) {
1107                 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1108         } else {
1109                 /* try 445 first, then 139 */
1110                 int port = cli->port?cli->port:445;
1111                 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1112                                           port, cli->timeout);
1113                 if (cli->fd == -1 && cli->port == 0) {
1114                         port = 139;
1115                         cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, 
1116                                                   port, cli->timeout);
1117                 }
1118                 if (cli->fd != -1)
1119                         cli->port = port;
1120         }
1121         if (cli->fd == -1) {
1122                 DEBUG(1,("Error connecting to %s (%s)\n",
1123                          ip?inet_ntoa(*ip):host,strerror(errno)));
1124                 return False;
1125         }
1126
1127         set_socket_options(cli->fd,user_socket_options);
1128
1129         return True;
1130 }
1131
1132 /****************************************************************************
1133  Initialise client credentials for authenticated pipe access.
1134 ****************************************************************************/
1135
1136 static void init_creds(struct ntuser_creds *creds, const char* username,
1137                        const char* domain, const char* password)
1138 {
1139         ZERO_STRUCTP(creds);
1140
1141         pwd_set_cleartext(&creds->pwd, password);
1142
1143         fstrcpy(creds->user_name, username);
1144         fstrcpy(creds->domain, domain);
1145
1146         if (!*username) {
1147                 creds->pwd.null_pwd = True;
1148         }
1149 }
1150
1151 /**
1152    establishes a connection right up to doing tconX, password specified.
1153    @param output_cli A fully initialised cli structure, non-null only on success
1154    @param dest_host The netbios name of the remote host
1155    @param dest_ip (optional) The the destination IP, NULL for name based lookup
1156    @param port (optional) The destination port (0 for default)
1157    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
1158    @param service_type The 'type' of serivice. 
1159    @param user Username, unix string
1160    @param domain User's domain
1161    @param password User's password, unencrypted unix string.
1162    @param retry BOOL. Did this connection fail with a retryable error ?
1163 */
1164
1165 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
1166                              const char *my_name, 
1167                              const char *dest_host, 
1168                              struct in_addr *dest_ip, int port,
1169                              const char *service, const char *service_type,
1170                              const char *user, const char *domain, 
1171                              const char *password, int flags,
1172                              BOOL *retry) 
1173 {
1174         struct ntuser_creds creds;
1175         NTSTATUS nt_status;
1176         struct nmb_name calling;
1177         struct nmb_name called;
1178         struct cli_state *cli;
1179         struct in_addr ip;
1180
1181         if (retry)
1182                 *retry = False;
1183
1184         if (!my_name) 
1185                 my_name = global_myname();
1186         
1187         if (!(cli = cli_initialise(NULL)))
1188                 return NT_STATUS_NO_MEMORY;
1189         
1190         make_nmb_name(&calling, my_name, 0x0);
1191         make_nmb_name(&called , dest_host, 0x20);
1192
1193         if (cli_set_port(cli, port) != port) {
1194                 cli_shutdown(cli);
1195                 return NT_STATUS_UNSUCCESSFUL;
1196         }
1197
1198         cli_set_timeout(cli, 10000); /* 10 seconds. */
1199
1200         if (dest_ip)
1201                 ip = *dest_ip;
1202         else
1203                 ZERO_STRUCT(ip);
1204
1205 again:
1206
1207         DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1208         
1209         if (!cli_connect(cli, dest_host, &ip)) {
1210                 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1211                          nmb_namestr(&called), inet_ntoa(ip)));
1212                 cli_shutdown(cli);
1213                 return NT_STATUS_UNSUCCESSFUL;
1214         }
1215
1216         if (retry)
1217                 *retry = True;
1218
1219         if (!cli_session_request(cli, &calling, &called)) {
1220                 char *p;
1221                 DEBUG(1,("session request to %s failed (%s)\n", 
1222                          called.name, cli_errstr(cli)));
1223                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1224                         *p = 0;
1225                         goto again;
1226                 }
1227                 if (strcmp(called.name, "*SMBSERVER")) {
1228                         make_nmb_name(&called , "*SMBSERVER", 0x20);
1229                         goto again;
1230                 }
1231                 return NT_STATUS_UNSUCCESSFUL;
1232         }
1233
1234         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1235                 cli->use_spnego = False;
1236         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1237                 cli->use_kerberos = True;
1238
1239         if (!cli_negprot(cli)) {
1240                 DEBUG(1,("failed negprot\n"));
1241                 nt_status = NT_STATUS_UNSUCCESSFUL;
1242                 cli_shutdown(cli);
1243                 return nt_status;
1244         }
1245
1246         if (!cli_session_setup(cli, user, password, strlen(password)+1, 
1247                                password, strlen(password)+1, 
1248                                domain)) {
1249                 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1250                     && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1251                 } else {
1252                         nt_status = cli_nt_error(cli);
1253                         DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1254                         cli_shutdown(cli);
1255                         if (NT_STATUS_IS_OK(nt_status)) 
1256                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1257                         return nt_status;
1258                 }
1259         } 
1260
1261         if (service) {
1262                 if (!cli_send_tconX(cli, service, service_type,
1263                                     password, strlen(password)+1)) {
1264                         nt_status = cli_nt_error(cli);
1265                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1266                         cli_shutdown(cli);
1267                         if (NT_STATUS_IS_OK(nt_status)) {
1268                                 nt_status = NT_STATUS_UNSUCCESSFUL;
1269                         }
1270                         return nt_status;
1271                 }
1272         }
1273
1274         init_creds(&creds, user, domain, password);
1275         cli_init_creds(cli, &creds);
1276
1277         *output_cli = cli;
1278         return NT_STATUS_OK;
1279 }
1280
1281 /****************************************************************************
1282  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1283 ****************************************************************************/
1284
1285 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1286                                      struct in_addr *pdest_ip)
1287 {
1288         struct nmb_name calling, called;
1289
1290         make_nmb_name(&calling, srchost, 0x0);
1291
1292         /*
1293          * If the called name is an IP address
1294          * then use *SMBSERVER immediately.
1295          */
1296
1297         if(is_ipaddress(desthost))
1298                 make_nmb_name(&called, "*SMBSERVER", 0x20);
1299         else
1300                 make_nmb_name(&called, desthost, 0x20);
1301
1302         if (!cli_session_request(cli, &calling, &called)) {
1303                 struct nmb_name smbservername;
1304
1305                 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1306
1307                 /*
1308                  * If the name wasn't *SMBSERVER then
1309                  * try with *SMBSERVER if the first name fails.
1310                  */
1311
1312                 if (nmb_name_equal(&called, &smbservername)) {
1313
1314                         /*
1315                          * The name used was *SMBSERVER, don't bother with another name.
1316                          */
1317
1318                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1319 with error %s.\n", desthost, cli_errstr(cli) ));
1320                         return False;
1321                 }
1322
1323                 /*
1324                  * We need to close the connection here but can't call cli_shutdown as
1325                  * will free an allocated cli struct. cli_close_connection was invented
1326                  * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1327                  */
1328
1329                 cli_close_connection(cli);
1330
1331                 if (!cli_initialise(cli) ||
1332                                 !cli_connect(cli, desthost, pdest_ip) ||
1333                                 !cli_session_request(cli, &calling, &smbservername)) {
1334                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1335 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1336                         return False;
1337                 }
1338         }
1339
1340         return True;
1341 }
1342
1343
1344
1345
1346
1347 /****************************************************************************
1348  Send an old style tcon.
1349 ****************************************************************************/
1350 NTSTATUS cli_raw_tcon(struct cli_state *cli, 
1351                       const char *service, const char *pass, const char *dev,
1352                       uint16 *max_xmit, uint16 *tid)
1353 {
1354         char *p;
1355
1356         memset(cli->outbuf,'\0',smb_size);
1357         memset(cli->inbuf,'\0',smb_size);
1358
1359         set_message(cli->outbuf, 0, 0, True);
1360         SCVAL(cli->outbuf,smb_com,SMBtcon);
1361         cli_setup_packet(cli);
1362
1363         p = smb_buf(cli->outbuf);
1364         *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
1365         *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
1366         *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
1367
1368         cli_setup_bcc(cli, p);
1369
1370         cli_send_smb(cli);
1371         if (!cli_receive_smb(cli)) {
1372                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1373         }
1374
1375         if (cli_is_error(cli)) {
1376                 return cli_nt_error(cli);
1377         }
1378
1379         *max_xmit = SVAL(cli->inbuf, smb_vwv0);
1380         *tid = SVAL(cli->inbuf, smb_vwv1);
1381
1382         return NT_STATUS_OK;
1383 }
1384
1385 /* Return a cli_state pointing at the IPC$ share for the given server */
1386
1387 struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
1388                                          struct user_auth_info *user_info)
1389 {
1390         struct cli_state *cli;
1391         pstring myname;
1392         NTSTATUS nt_status;
1393
1394         get_myname(myname);
1395         
1396         nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC", 
1397                                         user_info->username, lp_workgroup(), user_info->password, 
1398                                         CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, NULL);
1399
1400         if (NT_STATUS_IS_OK(nt_status)) {
1401                 return cli;
1402         } else if (is_ipaddress(server)) {
1403             /* windows 9* needs a correct NMB name for connections */
1404             fstring remote_name;
1405
1406             if (name_status_find("*", 0, 0, *server_ip, remote_name)) {
1407                 cli = get_ipc_connect(remote_name, server_ip, user_info);
1408                 if (cli)
1409                     return cli;
1410             }
1411         }
1412         return NULL;
1413 }
1414
1415 /* Return the IP address and workgroup of a master browser on the 
1416    network. */
1417
1418 struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
1419 {
1420         struct in_addr *ip_list;
1421         struct cli_state *cli;
1422         int i, count;
1423         struct in_addr server_ip; 
1424
1425         /* Go looking for workgroups by broadcasting on the local network */ 
1426
1427         if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
1428                 return False;
1429         }
1430
1431         for (i = 0; i < count; i++) {
1432                 static fstring name;
1433
1434                 if (!name_status_find("*", 0, 0x1d, ip_list[i], name))
1435                         continue;
1436
1437                 if (!find_master_ip(name, &server_ip))
1438                         continue;
1439
1440                 pstrcpy(workgroup, name);
1441
1442                 DEBUG(4, ("found master browser %s, %s\n", 
1443                           name, inet_ntoa(ip_list[i])));
1444
1445                 cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
1446
1447                 if (!cli)
1448                     continue;
1449                 
1450                 return cli;
1451         }
1452
1453         return NULL;
1454 }