r15: syncing for 3.0.3pre2
[Samba.git] / source / libsmb / cliconnect.c
blobcdf58c5b9130d59c0225f84532974d1f89121370
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
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.
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.
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.
22 #define NO_SYSLOG
24 #include "includes.h"
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}
43 /****************************************************************************
44 Do an old lanman2 style session setup.
45 ****************************************************************************/
47 static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user,
48 const char *pass, size_t passlen, const char *workgroup)
50 fstring pword;
51 char *p;
53 if (passlen > sizeof(pword)-1)
54 return False;
56 /* LANMAN servers predate NT status codes and Unicode and ignore those
57 smb flags so we must disable the corresponding default capabilities
58 that would otherwise cause the Unicode and NT Status flags to be
59 set (and even returned by the server) */
61 cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
63 /* if in share level security then don't send a password now */
64 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
65 passlen = 0;
67 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
68 /* Encrypted mode needed, and non encrypted password supplied. */
69 passlen = 24;
70 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
71 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
72 /* Encrypted mode needed, and encrypted password supplied. */
73 memcpy(pword, pass, passlen);
74 } else if (passlen > 0) {
75 /* Plaintext mode needed, assume plaintext supplied. */
76 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
79 /* send a session setup command */
80 memset(cli->outbuf,'\0',smb_size);
81 set_message(cli->outbuf,10, 0, True);
82 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
83 cli_setup_packet(cli);
85 SCVAL(cli->outbuf,smb_vwv0,0xFF);
86 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
87 SSVAL(cli->outbuf,smb_vwv3,2);
88 SSVAL(cli->outbuf,smb_vwv4,1);
89 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
90 SSVAL(cli->outbuf,smb_vwv7,passlen);
92 p = smb_buf(cli->outbuf);
93 memcpy(p,pword,passlen);
94 p += passlen;
95 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
96 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
97 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
98 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
99 cli_setup_bcc(cli, p);
101 cli_send_smb(cli);
102 if (!cli_receive_smb(cli))
103 return False;
105 show_msg(cli->inbuf);
107 if (cli_is_error(cli))
108 return False;
110 /* use the returned vuid from now on */
111 cli->vuid = SVAL(cli->inbuf,smb_uid);
112 fstrcpy(cli->user_name, user);
114 return True;
117 /****************************************************************************
118 Work out suitable capabilities to offer the server.
119 ****************************************************************************/
121 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
123 uint32 capabilities = CAP_NT_SMBS;
125 if (!cli->force_dos_errors)
126 capabilities |= CAP_STATUS32;
128 if (cli->use_level_II_oplocks)
129 capabilities |= CAP_LEVEL_II_OPLOCKS;
131 if (cli->capabilities & CAP_UNICODE)
132 capabilities |= CAP_UNICODE;
134 if (cli->capabilities & CAP_LARGE_FILES)
135 capabilities |= CAP_LARGE_FILES;
137 return capabilities;
140 /****************************************************************************
141 Do a NT1 guest session setup.
142 ****************************************************************************/
144 static BOOL cli_session_setup_guest(struct cli_state *cli)
146 char *p;
147 uint32 capabilities = cli_session_setup_capabilities(cli);
149 set_message(cli->outbuf,13,0,True);
150 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
151 cli_setup_packet(cli);
153 SCVAL(cli->outbuf,smb_vwv0,0xFF);
154 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
155 SSVAL(cli->outbuf,smb_vwv3,2);
156 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
157 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
158 SSVAL(cli->outbuf,smb_vwv7,0);
159 SSVAL(cli->outbuf,smb_vwv8,0);
160 SIVAL(cli->outbuf,smb_vwv11,capabilities);
161 p = smb_buf(cli->outbuf);
162 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
163 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
164 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
165 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
166 cli_setup_bcc(cli, p);
168 cli_send_smb(cli);
169 if (!cli_receive_smb(cli))
170 return False;
172 show_msg(cli->inbuf);
174 if (cli_is_error(cli))
175 return False;
177 cli->vuid = SVAL(cli->inbuf,smb_uid);
179 p = smb_buf(cli->inbuf);
180 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
181 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
182 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
184 fstrcpy(cli->user_name, "");
186 return True;
189 /****************************************************************************
190 Do a NT1 plaintext session setup.
191 ****************************************************************************/
193 static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user,
194 const char *pass, const char *workgroup)
196 uint32 capabilities = cli_session_setup_capabilities(cli);
197 char *p;
198 fstring lanman;
200 fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
202 set_message(cli->outbuf,13,0,True);
203 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
204 cli_setup_packet(cli);
206 SCVAL(cli->outbuf,smb_vwv0,0xFF);
207 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
208 SSVAL(cli->outbuf,smb_vwv3,2);
209 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
210 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
211 SSVAL(cli->outbuf,smb_vwv8,0);
212 SIVAL(cli->outbuf,smb_vwv11,capabilities);
213 p = smb_buf(cli->outbuf);
215 /* check wether to send the ASCII or UNICODE version of the password */
217 if ( (capabilities & CAP_UNICODE) == 0 ) {
218 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
219 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
221 else {
222 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
223 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf)));
226 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
227 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
228 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
229 p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
230 cli_setup_bcc(cli, p);
232 cli_send_smb(cli);
233 if (!cli_receive_smb(cli))
234 return False;
236 show_msg(cli->inbuf);
238 if (cli_is_error(cli))
239 return False;
241 cli->vuid = SVAL(cli->inbuf,smb_uid);
242 p = smb_buf(cli->inbuf);
243 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
244 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
245 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
246 fstrcpy(cli->user_name, user);
248 return True;
252 * Set the user session key for a connection
253 * @param cli The cli structure to add it too
254 * @param session_key The session key used. (A copy of this is taken for the cli struct)
258 static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
260 cli->user_session_key = data_blob(session_key.data, session_key.length);
263 /****************************************************************************
264 do a NT1 NTLM/LM encrypted session setup - for when extended security
265 is not negotiated.
266 @param cli client state to create do session setup on
267 @param user username
268 @param pass *either* cleartext password (passlen !=24) or LM response.
269 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
270 @param workgroup The user's domain.
271 ****************************************************************************/
273 static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user,
274 const char *pass, size_t passlen,
275 const char *ntpass, size_t ntpasslen,
276 const char *workgroup)
278 uint32 capabilities = cli_session_setup_capabilities(cli);
279 DATA_BLOB lm_response = data_blob(NULL, 0);
280 DATA_BLOB nt_response = data_blob(NULL, 0);
281 DATA_BLOB session_key = data_blob(NULL, 0);
282 BOOL ret = False;
283 char *p;
285 if (passlen == 0) {
286 /* do nothing - guest login */
287 } else if (passlen != 24) {
288 if (lp_client_ntlmv2_auth()) {
289 DATA_BLOB server_chal;
290 DATA_BLOB names_blob;
291 server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
293 /* note that the 'workgroup' here is a best guess - we don't know
294 the server's domain at this point. The 'server name' is also
295 dodgy...
297 names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
299 if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal,
300 &names_blob,
301 &lm_response, &nt_response, &session_key)) {
302 data_blob_free(&names_blob);
303 data_blob_free(&server_chal);
304 return False;
306 data_blob_free(&names_blob);
307 data_blob_free(&server_chal);
309 } else {
310 uchar nt_hash[16];
311 E_md4hash(pass, nt_hash);
313 nt_response = data_blob(NULL, 24);
314 SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
316 /* non encrypted password supplied. Ignore ntpass. */
317 if (lp_client_lanman_auth()) {
318 lm_response = data_blob(NULL, 24);
319 SMBencrypt(pass,cli->secblob.data, lm_response.data);
320 } else {
321 /* LM disabled, place NT# in LM field instead */
322 lm_response = data_blob(nt_response.data, nt_response.length);
325 session_key = data_blob(NULL, 16);
326 SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
328 cli_simple_set_signing(cli, session_key, nt_response);
329 } else {
330 /* pre-encrypted password supplied. Only used for
331 security=server, can't do
332 signing because we don't have original key */
334 lm_response = data_blob(pass, passlen);
335 nt_response = data_blob(ntpass, ntpasslen);
338 /* send a session setup command */
339 memset(cli->outbuf,'\0',smb_size);
341 set_message(cli->outbuf,13,0,True);
342 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
343 cli_setup_packet(cli);
345 SCVAL(cli->outbuf,smb_vwv0,0xFF);
346 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
347 SSVAL(cli->outbuf,smb_vwv3,2);
348 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
349 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
350 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
351 SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
352 SIVAL(cli->outbuf,smb_vwv11,capabilities);
353 p = smb_buf(cli->outbuf);
354 if (lm_response.length) {
355 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
357 if (nt_response.length) {
358 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
360 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
362 /* Upper case here might help some NTLMv2 implementations */
363 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
364 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
365 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
366 cli_setup_bcc(cli, p);
368 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
369 ret = False;
370 goto end;
373 /* show_msg(cli->inbuf); */
375 if (cli_is_error(cli)) {
376 ret = False;
377 goto end;
380 /* use the returned vuid from now on */
381 cli->vuid = SVAL(cli->inbuf,smb_uid);
383 p = smb_buf(cli->inbuf);
384 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
385 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
386 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
388 fstrcpy(cli->user_name, user);
390 if (session_key.data) {
391 /* Have plaintext orginal */
392 cli_set_session_key(cli, session_key);
395 ret = True;
396 end:
397 data_blob_free(&lm_response);
398 data_blob_free(&nt_response);
400 if (!ret)
401 data_blob_free(&session_key);
402 return ret;
405 /****************************************************************************
406 Send a extended security session setup blob
407 ****************************************************************************/
409 static BOOL cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
411 uint32 capabilities = cli_session_setup_capabilities(cli);
412 char *p;
414 capabilities |= CAP_EXTENDED_SECURITY;
416 /* send a session setup command */
417 memset(cli->outbuf,'\0',smb_size);
419 set_message(cli->outbuf,12,0,True);
420 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
422 cli_setup_packet(cli);
424 SCVAL(cli->outbuf,smb_vwv0,0xFF);
425 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
426 SSVAL(cli->outbuf,smb_vwv3,2);
427 SSVAL(cli->outbuf,smb_vwv4,1);
428 SIVAL(cli->outbuf,smb_vwv5,0);
429 SSVAL(cli->outbuf,smb_vwv7,blob.length);
430 SIVAL(cli->outbuf,smb_vwv10,capabilities);
431 p = smb_buf(cli->outbuf);
432 memcpy(p, blob.data, blob.length);
433 p += blob.length;
434 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
435 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
436 cli_setup_bcc(cli, p);
437 return cli_send_smb(cli);
440 /****************************************************************************
441 Send a extended security session setup blob, returning a reply blob.
442 ****************************************************************************/
444 static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
446 DATA_BLOB blob2 = data_blob(NULL, 0);
447 char *p;
448 size_t len;
450 if (!cli_receive_smb(cli))
451 return blob2;
453 show_msg(cli->inbuf);
455 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
456 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
457 return blob2;
460 /* use the returned vuid from now on */
461 cli->vuid = SVAL(cli->inbuf,smb_uid);
463 p = smb_buf(cli->inbuf);
465 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
467 p += blob2.length;
468 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
470 /* w2k with kerberos doesn't properly null terminate this field */
471 len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
472 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
474 return blob2;
477 #ifdef HAVE_KRB5
479 /****************************************************************************
480 Send a extended security session setup blob, returning a reply blob.
481 ****************************************************************************/
483 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
485 DATA_BLOB blob2 = data_blob(NULL, 0);
486 if (!cli_session_setup_blob_send(cli, blob)) {
487 return blob2;
490 return cli_session_setup_blob_receive(cli);
493 /****************************************************************************
494 Use in-memory credentials cache
495 ****************************************************************************/
497 static void use_in_memory_ccache(void) {
498 setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
501 /****************************************************************************
502 Do a spnego/kerberos encrypted session setup.
503 ****************************************************************************/
505 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
507 DATA_BLOB blob2, negTokenTarg;
508 DATA_BLOB session_key_krb5;
509 DATA_BLOB null_blob = data_blob(NULL, 0);
510 int rc;
512 DEBUG(2,("Doing kerberos session setup\n"));
514 /* generate the encapsulated kerberos5 ticket */
515 rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5);
517 if (rc) {
518 DEBUG(1, ("spnego_gen_negTokenTarg failed: %s\n", error_message(rc)));
519 return ADS_ERROR_KRB5(rc);
522 #if 0
523 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
524 #endif
526 cli_simple_set_signing(cli, session_key_krb5, null_blob);
528 blob2 = cli_session_setup_blob(cli, negTokenTarg);
530 /* we don't need this blob for kerberos */
531 data_blob_free(&blob2);
533 cli_set_session_key(cli, session_key_krb5);
535 data_blob_free(&negTokenTarg);
537 if (cli_is_error(cli)) {
538 if (NT_STATUS_IS_OK(cli_nt_error(cli))) {
539 return ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
542 return ADS_ERROR_NT(cli_nt_error(cli));
544 #endif /* HAVE_KRB5 */
547 /****************************************************************************
548 Do a spnego/NTLMSSP encrypted session setup.
549 ****************************************************************************/
551 static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
552 const char *pass, const char *domain)
554 struct ntlmssp_state *ntlmssp_state;
555 NTSTATUS nt_status;
556 int turn = 1;
557 DATA_BLOB msg1;
558 DATA_BLOB blob;
559 DATA_BLOB blob_in = data_blob(NULL, 0);
560 DATA_BLOB blob_out;
562 cli_temp_set_signing(cli);
564 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
565 return nt_status;
568 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
569 return nt_status;
571 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
572 return nt_status;
574 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
575 return nt_status;
578 do {
579 nt_status = ntlmssp_update(ntlmssp_state,
580 blob_in, &blob_out);
581 data_blob_free(&blob_in);
582 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
583 if (turn == 1) {
584 /* and wrap it in a SPNEGO wrapper */
585 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
586 } else {
587 /* wrap it in SPNEGO */
588 msg1 = spnego_gen_auth(blob_out);
591 /* now send that blob on its way */
592 if (!cli_session_setup_blob_send(cli, msg1)) {
593 DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
594 nt_status = NT_STATUS_UNSUCCESSFUL;
595 } else {
596 data_blob_free(&msg1);
598 blob = cli_session_setup_blob_receive(cli);
600 nt_status = cli_nt_error(cli);
601 if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
602 if (cli->smb_rw_error == READ_BAD_SIG) {
603 nt_status = NT_STATUS_ACCESS_DENIED;
604 } else {
605 nt_status = NT_STATUS_UNSUCCESSFUL;
611 if (!blob.length) {
612 if (NT_STATUS_IS_OK(nt_status)) {
613 nt_status = NT_STATUS_UNSUCCESSFUL;
615 } else if ((turn == 1) &&
616 NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
617 DATA_BLOB tmp_blob = data_blob(NULL, 0);
618 /* the server might give us back two challenges */
619 if (!spnego_parse_challenge(blob, &blob_in,
620 &tmp_blob)) {
621 DEBUG(3,("Failed to parse challenges\n"));
622 nt_status = NT_STATUS_INVALID_PARAMETER;
624 data_blob_free(&tmp_blob);
625 } else {
626 if (!spnego_parse_auth_response(blob, nt_status,
627 &blob_in)) {
628 DEBUG(3,("Failed to parse auth response\n"));
629 if (NT_STATUS_IS_OK(nt_status)
630 || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED))
631 nt_status = NT_STATUS_INVALID_PARAMETER;
634 data_blob_free(&blob);
635 data_blob_free(&blob_out);
636 turn++;
637 } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
639 if (NT_STATUS_IS_OK(nt_status)) {
641 DATA_BLOB key = data_blob(ntlmssp_state->session_key.data,
642 ntlmssp_state->session_key.length);
643 DATA_BLOB null_blob = data_blob(NULL, 0);
645 fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
646 cli_set_session_key(cli, ntlmssp_state->session_key);
648 if (cli_simple_set_signing(cli, key, null_blob)) {
650 /* 'resign' the last message, so we get the right sequence numbers
651 for checking the first reply from the server */
652 cli_calculate_sign_mac(cli);
654 if (!cli_check_sign_mac(cli, True)) {
655 nt_status = NT_STATUS_ACCESS_DENIED;
660 /* we have a reference conter on ntlmssp_state, if we are signing
661 then the state will be kept by the signing engine */
663 ntlmssp_end(&ntlmssp_state);
665 return nt_status;
668 /****************************************************************************
669 Do a spnego encrypted session setup.
670 ****************************************************************************/
672 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
673 const char *pass, const char *domain)
675 char *principal;
676 char *OIDs[ASN1_MAX_OIDS];
677 int i;
678 BOOL got_kerberos_mechanism = False;
679 DATA_BLOB blob;
681 DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
683 /* the server might not even do spnego */
684 if (cli->secblob.length <= 16) {
685 DEBUG(3,("server didn't supply a full spnego negprot\n"));
686 goto ntlmssp;
689 #if 0
690 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
691 #endif
693 /* there is 16 bytes of GUID before the real spnego packet starts */
694 blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
696 /* the server sent us the first part of the SPNEGO exchange in the negprot
697 reply */
698 if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
699 data_blob_free(&blob);
700 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
702 data_blob_free(&blob);
704 /* make sure the server understands kerberos */
705 for (i=0;OIDs[i];i++) {
706 DEBUG(3,("got OID=%s\n", OIDs[i]));
707 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
708 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
709 got_kerberos_mechanism = True;
711 free(OIDs[i]);
713 DEBUG(3,("got principal=%s\n", principal));
715 fstrcpy(cli->user_name, user);
717 #ifdef HAVE_KRB5
718 /* If password is set we reauthenticate to kerberos server
719 * and do not store results */
721 if (got_kerberos_mechanism && cli->use_kerberos) {
722 if (pass && *pass) {
723 int ret;
725 use_in_memory_ccache();
726 ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
728 if (ret){
729 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
730 return ADS_ERROR_KRB5(ret);
734 return cli_session_setup_kerberos(cli, principal, domain);
736 #endif
738 free(principal);
740 ntlmssp:
742 return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, user, pass, domain));
745 /****************************************************************************
746 Send a session setup. The username and workgroup is in UNIX character
747 format and must be converted to DOS codepage format before sending. If the
748 password is in plaintext, the same should be done.
749 ****************************************************************************/
751 BOOL cli_session_setup(struct cli_state *cli,
752 const char *user,
753 const char *pass, int passlen,
754 const char *ntpass, int ntpasslen,
755 const char *workgroup)
757 char *p;
758 fstring user2;
760 /* allow for workgroups as part of the username */
761 fstrcpy(user2, user);
762 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
763 (p=strchr_m(user2,*lp_winbind_separator()))) {
764 *p = 0;
765 user = p+1;
766 workgroup = user2;
769 if (cli->protocol < PROTOCOL_LANMAN1)
770 return True;
772 /* now work out what sort of session setup we are going to
773 do. I have split this into separate functions to make the
774 flow a bit easier to understand (tridge) */
776 /* if its an older server then we have to use the older request format */
778 if (cli->protocol < PROTOCOL_NT1) {
779 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
780 DEBUG(1, ("Server requested LM password but 'client lanman auth'"
781 " is disabled\n"));
782 return False;
785 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
786 !lp_client_plaintext_auth() && (*pass)) {
787 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
788 " is disabled\n"));
789 return False;
792 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
795 /* if no user is supplied then we have to do an anonymous connection.
796 passwords are ignored */
798 if (!user || !*user)
799 return cli_session_setup_guest(cli);
801 /* if the server is share level then send a plaintext null
802 password at this point. The password is sent in the tree
803 connect */
805 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
806 return cli_session_setup_plaintext(cli, user, "", workgroup);
808 /* if the server doesn't support encryption then we have to use
809 plaintext. The second password is ignored */
811 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
812 if (!lp_client_plaintext_auth() && (*pass)) {
813 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
814 " is disabled\n"));
815 return False;
817 return cli_session_setup_plaintext(cli, user, pass, workgroup);
820 /* if the server supports extended security then use SPNEGO */
822 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
823 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass, workgroup);
824 if (!ADS_ERR_OK(status)) {
825 DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
826 return False;
828 return True;
831 /* otherwise do a NT1 style session setup */
833 return cli_session_setup_nt1(cli, user,
834 pass, passlen, ntpass, ntpasslen,
835 workgroup);
838 /****************************************************************************
839 Send a uloggoff.
840 *****************************************************************************/
842 BOOL cli_ulogoff(struct cli_state *cli)
844 memset(cli->outbuf,'\0',smb_size);
845 set_message(cli->outbuf,2,0,True);
846 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
847 cli_setup_packet(cli);
848 SSVAL(cli->outbuf,smb_vwv0,0xFF);
849 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
851 cli_send_smb(cli);
852 if (!cli_receive_smb(cli))
853 return False;
855 return !cli_is_error(cli);
858 /****************************************************************************
859 Send a tconX.
860 ****************************************************************************/
861 BOOL cli_send_tconX(struct cli_state *cli,
862 const char *share, const char *dev, const char *pass, int passlen)
864 fstring fullshare, pword;
865 char *p;
866 memset(cli->outbuf,'\0',smb_size);
867 memset(cli->inbuf,'\0',smb_size);
869 fstrcpy(cli->share, share);
871 /* in user level security don't send a password now */
872 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
873 passlen = 1;
874 pass = "";
877 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
878 if (!lp_client_lanman_auth()) {
879 DEBUG(1, ("Server requested LANMAN password (share-level security) but 'client use lanman auth'"
880 " is disabled\n"));
881 return False;
885 * Non-encrypted passwords - convert to DOS codepage before encryption.
887 passlen = 24;
888 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
889 } else {
890 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
891 if (!lp_client_plaintext_auth() && (*pass)) {
892 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
893 " is disabled\n"));
894 return False;
898 * Non-encrypted passwords - convert to DOS codepage before using.
900 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
902 } else {
903 memcpy(pword, pass, passlen);
907 slprintf(fullshare, sizeof(fullshare)-1,
908 "\\\\%s\\%s", cli->desthost, share);
910 set_message(cli->outbuf,4, 0, True);
911 SCVAL(cli->outbuf,smb_com,SMBtconX);
912 cli_setup_packet(cli);
914 SSVAL(cli->outbuf,smb_vwv0,0xFF);
915 SSVAL(cli->outbuf,smb_vwv3,passlen);
917 p = smb_buf(cli->outbuf);
918 memcpy(p,pword,passlen);
919 p += passlen;
920 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
921 p += clistr_push(cli, p, dev, -1, STR_TERMINATE |STR_UPPER | STR_ASCII);
923 cli_setup_bcc(cli, p);
925 cli_send_smb(cli);
926 if (!cli_receive_smb(cli))
927 return False;
929 if (cli_is_error(cli))
930 return False;
932 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
934 if (cli->protocol >= PROTOCOL_NT1 &&
935 smb_buflen(cli->inbuf) == 3) {
936 /* almost certainly win95 - enable bug fixes */
937 cli->win95 = True;
940 cli->cnum = SVAL(cli->inbuf,smb_tid);
941 return True;
944 /****************************************************************************
945 Send a tree disconnect.
946 ****************************************************************************/
948 BOOL cli_tdis(struct cli_state *cli)
950 memset(cli->outbuf,'\0',smb_size);
951 set_message(cli->outbuf,0,0,True);
952 SCVAL(cli->outbuf,smb_com,SMBtdis);
953 SSVAL(cli->outbuf,smb_tid,cli->cnum);
954 cli_setup_packet(cli);
956 cli_send_smb(cli);
957 if (!cli_receive_smb(cli))
958 return False;
960 return !cli_is_error(cli);
963 /****************************************************************************
964 Send a negprot command.
965 ****************************************************************************/
967 void cli_negprot_send(struct cli_state *cli)
969 char *p;
970 int numprots;
972 if (cli->protocol < PROTOCOL_NT1)
973 cli->use_spnego = False;
975 memset(cli->outbuf,'\0',smb_size);
977 /* setup the protocol strings */
978 set_message(cli->outbuf,0,0,True);
980 p = smb_buf(cli->outbuf);
981 for (numprots=0;
982 prots[numprots].name && prots[numprots].prot<=cli->protocol;
983 numprots++) {
984 *p++ = 2;
985 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
988 SCVAL(cli->outbuf,smb_com,SMBnegprot);
989 cli_setup_bcc(cli, p);
990 cli_setup_packet(cli);
992 SCVAL(smb_buf(cli->outbuf),0,2);
994 cli_send_smb(cli);
997 /****************************************************************************
998 Send a negprot command.
999 ****************************************************************************/
1001 BOOL cli_negprot(struct cli_state *cli)
1003 char *p;
1004 int numprots;
1005 int plength;
1007 if (cli->protocol < PROTOCOL_NT1)
1008 cli->use_spnego = False;
1010 memset(cli->outbuf,'\0',smb_size);
1012 /* setup the protocol strings */
1013 for (plength=0,numprots=0;
1014 prots[numprots].name && prots[numprots].prot<=cli->protocol;
1015 numprots++)
1016 plength += strlen(prots[numprots].name)+2;
1018 set_message(cli->outbuf,0,plength,True);
1020 p = smb_buf(cli->outbuf);
1021 for (numprots=0;
1022 prots[numprots].name && prots[numprots].prot<=cli->protocol;
1023 numprots++) {
1024 *p++ = 2;
1025 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1028 SCVAL(cli->outbuf,smb_com,SMBnegprot);
1029 cli_setup_packet(cli);
1031 SCVAL(smb_buf(cli->outbuf),0,2);
1033 cli_send_smb(cli);
1034 if (!cli_receive_smb(cli))
1035 return False;
1037 show_msg(cli->inbuf);
1039 if (cli_is_error(cli) ||
1040 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
1041 return(False);
1044 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
1046 if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
1047 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
1048 return False;
1051 if (cli->protocol >= PROTOCOL_NT1) {
1052 /* NT protocol */
1053 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
1054 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
1055 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
1056 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
1057 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
1058 cli->serverzone *= 60;
1059 /* this time arrives in real GMT */
1060 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
1061 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1062 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
1063 if (cli->capabilities & CAP_RAW_MODE) {
1064 cli->readbraw_supported = True;
1065 cli->writebraw_supported = True;
1067 /* work out if they sent us a workgroup */
1068 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1069 smb_buflen(cli->inbuf) > 8) {
1070 clistr_pull(cli, cli->server_domain,
1071 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
1072 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
1076 * As signing is slow we only turn it on if either the client or
1077 * the server require it. JRA.
1080 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
1081 /* Fail if server says signing is mandatory and we don't want to support it. */
1082 if (!cli->sign_info.allow_smb_signing) {
1083 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1084 return False;
1086 cli->sign_info.negotiated_smb_signing = True;
1087 cli->sign_info.mandatory_signing = True;
1088 } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
1089 /* Fail if client says signing is mandatory and the server doesn't support it. */
1090 if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
1091 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1092 return False;
1094 cli->sign_info.negotiated_smb_signing = True;
1095 cli->sign_info.mandatory_signing = True;
1096 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
1097 cli->sign_info.negotiated_smb_signing = True;
1100 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1101 cli->use_spnego = False;
1102 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
1103 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
1104 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
1105 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
1106 cli->serverzone *= 60;
1107 /* this time is converted to GMT by make_unix_date */
1108 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
1109 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
1110 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
1111 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
1112 } else {
1113 /* the old core protocol */
1114 cli->use_spnego = False;
1115 cli->sec_mode = 0;
1116 cli->serverzone = TimeDiff(time(NULL));
1119 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1121 /* a way to force ascii SMB */
1122 if (getenv("CLI_FORCE_ASCII"))
1123 cli->capabilities &= ~CAP_UNICODE;
1125 return True;
1128 /****************************************************************************
1129 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1130 ****************************************************************************/
1132 BOOL cli_session_request(struct cli_state *cli,
1133 struct nmb_name *calling, struct nmb_name *called)
1135 char *p;
1136 int len = 4;
1137 extern pstring user_socket_options;
1139 memcpy(&(cli->calling), calling, sizeof(*calling));
1140 memcpy(&(cli->called ), called , sizeof(*called ));
1142 /* put in the destination name */
1143 p = cli->outbuf+len;
1144 name_mangle(cli->called .name, p, cli->called .name_type);
1145 len += name_len(p);
1147 /* and my name */
1148 p = cli->outbuf+len;
1149 name_mangle(cli->calling.name, p, cli->calling.name_type);
1150 len += name_len(p);
1152 /* 445 doesn't have session request */
1153 if (cli->port == 445)
1154 return True;
1156 /* send a session request (RFC 1002) */
1157 /* setup the packet length
1158 * Remove four bytes from the length count, since the length
1159 * field in the NBT Session Service header counts the number
1160 * of bytes which follow. The cli_send_smb() function knows
1161 * about this and accounts for those four bytes.
1162 * CRH.
1164 len -= 4;
1165 _smb_setlen(cli->outbuf,len);
1166 SCVAL(cli->outbuf,0,0x81);
1168 cli_send_smb(cli);
1169 DEBUG(5,("Sent session request\n"));
1171 if (!cli_receive_smb(cli))
1172 return False;
1174 if (CVAL(cli->inbuf,0) == 0x84) {
1175 /* C. Hoch 9/14/95 Start */
1176 /* For information, here is the response structure.
1177 * We do the byte-twiddling to for portability.
1178 struct RetargetResponse{
1179 unsigned char type;
1180 unsigned char flags;
1181 int16 length;
1182 int32 ip_addr;
1183 int16 port;
1186 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1187 /* SESSION RETARGET */
1188 putip((char *)&cli->dest_ip,cli->inbuf+4);
1190 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
1191 if (cli->fd == -1)
1192 return False;
1194 DEBUG(3,("Retargeted\n"));
1196 set_socket_options(cli->fd,user_socket_options);
1198 /* Try again */
1200 static int depth;
1201 BOOL ret;
1202 if (depth > 4) {
1203 DEBUG(0,("Retarget recursion - failing\n"));
1204 return False;
1206 depth++;
1207 ret = cli_session_request(cli, calling, called);
1208 depth--;
1209 return ret;
1211 } /* C. Hoch 9/14/95 End */
1213 if (CVAL(cli->inbuf,0) != 0x82) {
1214 /* This is the wrong place to put the error... JRA. */
1215 cli->rap_error = CVAL(cli->inbuf,4);
1216 return False;
1218 return(True);
1221 /****************************************************************************
1222 Open the client sockets.
1223 ****************************************************************************/
1225 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1227 extern pstring user_socket_options;
1228 int name_type = 0x20;
1229 char *p;
1231 /* reasonable default hostname */
1232 if (!host) host = "*SMBSERVER";
1234 fstrcpy(cli->desthost, host);
1236 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1237 if ((p = strchr(cli->desthost, '#'))) {
1238 name_type = strtol(p+1, NULL, 16);
1239 *p = 0;
1242 if (!ip || is_zero_ip(*ip)) {
1243 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1244 return False;
1246 if (ip) *ip = cli->dest_ip;
1247 } else {
1248 cli->dest_ip = *ip;
1251 if (getenv("LIBSMB_PROG")) {
1252 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1253 } else {
1254 /* try 445 first, then 139 */
1255 int port = cli->port?cli->port:445;
1256 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1257 port, cli->timeout);
1258 if (cli->fd == -1 && cli->port == 0) {
1259 port = 139;
1260 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1261 port, cli->timeout);
1263 if (cli->fd != -1)
1264 cli->port = port;
1266 if (cli->fd == -1) {
1267 DEBUG(1,("Error connecting to %s (%s)\n",
1268 ip?inet_ntoa(*ip):host,strerror(errno)));
1269 return False;
1272 set_socket_options(cli->fd,user_socket_options);
1274 return True;
1277 /****************************************************************************
1278 Initialise client credentials for authenticated pipe access.
1279 ****************************************************************************/
1281 void init_creds(struct ntuser_creds *creds, const char* username,
1282 const char* domain, const char* password)
1284 ZERO_STRUCTP(creds);
1286 pwd_set_cleartext(&creds->pwd, password);
1288 fstrcpy(creds->user_name, username);
1289 fstrcpy(creds->domain, domain);
1291 if (!*username) {
1292 creds->pwd.null_pwd = True;
1297 establishes a connection to after the negprot.
1298 @param output_cli A fully initialised cli structure, non-null only on success
1299 @param dest_host The netbios name of the remote host
1300 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1301 @param port (optional) The destination port (0 for default)
1302 @param retry BOOL. Did this connection fail with a retryable error ?
1305 NTSTATUS cli_start_connection(struct cli_state **output_cli,
1306 const char *my_name,
1307 const char *dest_host,
1308 struct in_addr *dest_ip, int port,
1309 int signing_state, int flags,
1310 BOOL *retry)
1312 NTSTATUS nt_status;
1313 struct nmb_name calling;
1314 struct nmb_name called;
1315 struct cli_state *cli;
1316 struct in_addr ip;
1318 if (retry)
1319 *retry = False;
1321 if (!my_name)
1322 my_name = global_myname();
1324 if (!(cli = cli_initialise(NULL)))
1325 return NT_STATUS_NO_MEMORY;
1327 make_nmb_name(&calling, my_name, 0x0);
1328 make_nmb_name(&called , dest_host, 0x20);
1330 if (cli_set_port(cli, port) != port) {
1331 cli_shutdown(cli);
1332 return NT_STATUS_UNSUCCESSFUL;
1335 cli_set_timeout(cli, 10000); /* 10 seconds. */
1337 if (dest_ip)
1338 ip = *dest_ip;
1339 else
1340 ZERO_STRUCT(ip);
1342 again:
1344 DEBUG(3,("Connecting to host=%s\n", dest_host));
1346 if (!cli_connect(cli, dest_host, &ip)) {
1347 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1348 nmb_namestr(&called), inet_ntoa(ip)));
1349 cli_shutdown(cli);
1350 return NT_STATUS_UNSUCCESSFUL;
1353 if (retry)
1354 *retry = True;
1356 if (!cli_session_request(cli, &calling, &called)) {
1357 char *p;
1358 DEBUG(1,("session request to %s failed (%s)\n",
1359 called.name, cli_errstr(cli)));
1360 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
1361 *p = 0;
1362 goto again;
1364 if (strcmp(called.name, "*SMBSERVER")) {
1365 make_nmb_name(&called , "*SMBSERVER", 0x20);
1366 goto again;
1368 return NT_STATUS_UNSUCCESSFUL;
1371 cli_setup_signing_state(cli, signing_state);
1373 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
1374 cli->use_spnego = False;
1375 else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
1376 cli->use_kerberos = True;
1378 if (!cli_negprot(cli)) {
1379 DEBUG(1,("failed negprot\n"));
1380 nt_status = NT_STATUS_UNSUCCESSFUL;
1381 cli_shutdown(cli);
1382 return nt_status;
1385 *output_cli = cli;
1386 return NT_STATUS_OK;
1391 establishes a connection right up to doing tconX, password specified.
1392 @param output_cli A fully initialised cli structure, non-null only on success
1393 @param dest_host The netbios name of the remote host
1394 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1395 @param port (optional) The destination port (0 for default)
1396 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1397 @param service_type The 'type' of serivice.
1398 @param user Username, unix string
1399 @param domain User's domain
1400 @param password User's password, unencrypted unix string.
1401 @param retry BOOL. Did this connection fail with a retryable error ?
1404 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1405 const char *my_name,
1406 const char *dest_host,
1407 struct in_addr *dest_ip, int port,
1408 const char *service, const char *service_type,
1409 const char *user, const char *domain,
1410 const char *password, int flags,
1411 int signing_state,
1412 BOOL *retry)
1414 struct ntuser_creds creds;
1415 NTSTATUS nt_status;
1416 struct cli_state *cli = NULL;
1418 nt_status = cli_start_connection(&cli, my_name, dest_host,
1419 dest_ip, port, signing_state, flags, retry);
1421 if (!NT_STATUS_IS_OK(nt_status)) {
1422 return nt_status;
1425 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1426 password, strlen(password)+1,
1427 domain)) {
1428 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1429 && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1430 } else {
1431 nt_status = cli_nt_error(cli);
1432 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1433 cli_shutdown(cli);
1434 if (NT_STATUS_IS_OK(nt_status))
1435 nt_status = NT_STATUS_UNSUCCESSFUL;
1436 return nt_status;
1440 if (service) {
1441 if (!cli_send_tconX(cli, service, service_type,
1442 password, strlen(password)+1)) {
1443 nt_status = cli_nt_error(cli);
1444 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1445 cli_shutdown(cli);
1446 if (NT_STATUS_IS_OK(nt_status)) {
1447 nt_status = NT_STATUS_UNSUCCESSFUL;
1449 return nt_status;
1453 init_creds(&creds, user, domain, password);
1454 cli_init_creds(cli, &creds);
1456 *output_cli = cli;
1457 return NT_STATUS_OK;
1460 /****************************************************************************
1461 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1462 ****************************************************************************/
1464 BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
1465 struct in_addr *pdest_ip)
1467 struct nmb_name calling, called;
1469 make_nmb_name(&calling, srchost, 0x0);
1472 * If the called name is an IP address
1473 * then use *SMBSERVER immediately.
1476 if(is_ipaddress(desthost))
1477 make_nmb_name(&called, "*SMBSERVER", 0x20);
1478 else
1479 make_nmb_name(&called, desthost, 0x20);
1481 if (!cli_session_request(cli, &calling, &called)) {
1482 struct nmb_name smbservername;
1484 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1487 * If the name wasn't *SMBSERVER then
1488 * try with *SMBSERVER if the first name fails.
1491 if (nmb_name_equal(&called, &smbservername)) {
1494 * The name used was *SMBSERVER, don't bother with another name.
1497 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1498 with error %s.\n", desthost, cli_errstr(cli) ));
1499 return False;
1503 * We need to close the connection here but can't call cli_shutdown as
1504 * will free an allocated cli struct. cli_close_connection was invented
1505 * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1508 cli_close_connection(cli);
1510 if (!cli_initialise(cli) ||
1511 !cli_connect(cli, desthost, pdest_ip) ||
1512 !cli_session_request(cli, &calling, &smbservername)) {
1513 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1514 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1515 return False;
1519 return True;
1526 /****************************************************************************
1527 Send an old style tcon.
1528 ****************************************************************************/
1529 NTSTATUS cli_raw_tcon(struct cli_state *cli,
1530 const char *service, const char *pass, const char *dev,
1531 uint16 *max_xmit, uint16 *tid)
1533 char *p;
1535 if (!lp_client_plaintext_auth() && (*pass)) {
1536 DEBUG(1, ("Server requested plaintext password but 'client use plaintext auth'"
1537 " is disabled\n"));
1538 return NT_STATUS_ACCESS_DENIED;
1541 memset(cli->outbuf,'\0',smb_size);
1542 memset(cli->inbuf,'\0',smb_size);
1544 set_message(cli->outbuf, 0, 0, True);
1545 SCVAL(cli->outbuf,smb_com,SMBtcon);
1546 cli_setup_packet(cli);
1548 p = smb_buf(cli->outbuf);
1549 *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
1550 *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
1551 *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
1553 cli_setup_bcc(cli, p);
1555 cli_send_smb(cli);
1556 if (!cli_receive_smb(cli)) {
1557 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1560 if (cli_is_error(cli)) {
1561 return cli_nt_error(cli);
1564 *max_xmit = SVAL(cli->inbuf, smb_vwv0);
1565 *tid = SVAL(cli->inbuf, smb_vwv1);
1567 return NT_STATUS_OK;
1570 /* Return a cli_state pointing at the IPC$ share for the given server */
1572 struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
1573 struct user_auth_info *user_info)
1575 struct cli_state *cli;
1576 pstring myname;
1577 NTSTATUS nt_status;
1579 get_myname(myname);
1581 nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC",
1582 user_info->username, lp_workgroup(), user_info->password,
1583 CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, Undefined, NULL);
1585 if (NT_STATUS_IS_OK(nt_status)) {
1586 return cli;
1587 } else if (is_ipaddress(server)) {
1588 /* windows 9* needs a correct NMB name for connections */
1589 fstring remote_name;
1591 if (name_status_find("*", 0, 0, *server_ip, remote_name)) {
1592 cli = get_ipc_connect(remote_name, server_ip, user_info);
1593 if (cli)
1594 return cli;
1597 return NULL;
1601 * Given the IP address of a master browser on the network, return its
1602 * workgroup and connect to it.
1604 * This function is provided to allow additional processing beyond what
1605 * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
1606 * browsers and obtain each master browsers' list of domains (in case the
1607 * first master browser is recently on the network and has not yet
1608 * synchronized with other master browsers and therefore does not yet have the
1609 * entire network browse list)
1612 struct cli_state *get_ipc_connect_master_ip(struct ip_service * mb_ip, pstring workgroup, struct user_auth_info *user_info)
1614 static fstring name;
1615 struct cli_state *cli;
1616 struct in_addr server_ip;
1618 DEBUG(99, ("Looking up name of master browser %s\n",
1619 inet_ntoa(mb_ip->ip)));
1622 * Do a name status query to find out the name of the master browser.
1623 * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
1624 * master browser will not respond to a wildcard query (or, at least,
1625 * an NT4 server acting as the domain master browser will not).
1627 * We might be able to use ONLY the query on MSBROWSE, but that's not
1628 * yet been tested with all Windows versions, so until it is, leave
1629 * the original wildcard query as the first choice and fall back to
1630 * MSBROWSE if the wildcard query fails.
1632 if (!name_status_find("*", 0, 0x1d, mb_ip->ip, name) &&
1633 !name_status_find(MSBROWSE, 1, 0x1d, mb_ip->ip, name)) {
1635 DEBUG(99, ("Could not retrieve name status for %s\n",
1636 inet_ntoa(mb_ip->ip)));
1637 return NULL;
1640 if (!find_master_ip(name, &server_ip)) {
1641 DEBUG(99, ("Could not find master ip for %s\n", name));
1642 return NULL;
1645 pstrcpy(workgroup, name);
1647 DEBUG(4, ("found master browser %s, %s\n",
1648 name, inet_ntoa(mb_ip->ip)));
1650 cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info);
1652 return cli;
1657 * Return the IP address and workgroup of a master browser on the network, and
1658 * connect to it.
1661 struct cli_state *get_ipc_connect_master_ip_bcast(pstring workgroup, struct user_auth_info *user_info)
1663 struct ip_service *ip_list;
1664 struct cli_state *cli;
1665 int i, count;
1667 DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
1669 /* Go looking for workgroups by broadcasting on the local network */
1671 if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
1672 DEBUG(99, ("No master browsers responded\n"));
1673 return False;
1676 for (i = 0; i < count; i++) {
1677 DEBUG(99, ("Found master browser %s\n", inet_ntoa(ip_list[i].ip)));
1679 cli = get_ipc_connect_master_ip(&ip_list[i], workgroup, user_info);
1680 if (cli)
1681 return(cli);
1684 return NULL;