Fix for CVE-2009-2906.
[Samba.git] / source3 / libsmb / cliconnect.c
blob8a3667dd0dcadbf03ffb396033614f7f97c10971
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 3 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, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
23 static const struct {
24 int prot;
25 const char name[24];
26 } prots[10] = {
27 {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"},
28 {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"},
29 {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"},
30 {PROTOCOL_LANMAN1, "LANMAN1.0"},
31 {PROTOCOL_LANMAN2, "LM1.2X002"},
32 {PROTOCOL_LANMAN2, "DOS LANMAN2.1"},
33 {PROTOCOL_LANMAN2, "LANMAN2.1"},
34 {PROTOCOL_LANMAN2, "Samba"},
35 {PROTOCOL_NT1, "NT LANMAN 1.0"},
36 {PROTOCOL_NT1, "NT LM 0.12"},
39 #define STAR_SMBSERVER "*SMBSERVER"
41 /**
42 * Set the user session key for a connection
43 * @param cli The cli structure to add it too
44 * @param session_key The session key used. (A copy of this is taken for the cli struct)
48 static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key)
50 cli->user_session_key = data_blob(session_key.data, session_key.length);
53 /****************************************************************************
54 Do an old lanman2 style session setup.
55 ****************************************************************************/
57 static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
58 const char *user,
59 const char *pass, size_t passlen,
60 const char *workgroup)
62 DATA_BLOB session_key = data_blob_null;
63 DATA_BLOB lm_response = data_blob_null;
64 NTSTATUS status;
65 fstring pword;
66 char *p;
68 if (passlen > sizeof(pword)-1) {
69 return NT_STATUS_INVALID_PARAMETER;
72 /* LANMAN servers predate NT status codes and Unicode and ignore those
73 smb flags so we must disable the corresponding default capabilities
74 that would otherwise cause the Unicode and NT Status flags to be
75 set (and even returned by the server) */
77 cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
79 /* if in share level security then don't send a password now */
80 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
81 passlen = 0;
83 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
84 /* Encrypted mode needed, and non encrypted password supplied. */
85 lm_response = data_blob(NULL, 24);
86 if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
87 DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
88 return NT_STATUS_ACCESS_DENIED;
90 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
91 /* Encrypted mode needed, and encrypted password supplied. */
92 lm_response = data_blob(pass, passlen);
93 } else if (passlen > 0) {
94 /* Plaintext mode needed, assume plaintext supplied. */
95 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
96 lm_response = data_blob(pass, passlen);
99 /* send a session setup command */
100 memset(cli->outbuf,'\0',smb_size);
101 cli_set_message(cli->outbuf,10, 0, True);
102 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
103 cli_setup_packet(cli);
105 SCVAL(cli->outbuf,smb_vwv0,0xFF);
106 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
107 SSVAL(cli->outbuf,smb_vwv3,2);
108 SSVAL(cli->outbuf,smb_vwv4,1);
109 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
110 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
112 p = smb_buf(cli->outbuf);
113 memcpy(p,lm_response.data,lm_response.length);
114 p += lm_response.length;
115 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
116 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
117 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
118 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
119 cli_setup_bcc(cli, p);
121 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
122 return cli_nt_error(cli);
125 show_msg(cli->inbuf);
127 if (cli_is_error(cli)) {
128 return cli_nt_error(cli);
131 /* use the returned vuid from now on */
132 cli->vuid = SVAL(cli->inbuf,smb_uid);
133 status = cli_set_username(cli, user);
134 if (!NT_STATUS_IS_OK(status)) {
135 return status;
138 if (session_key.data) {
139 /* Have plaintext orginal */
140 cli_set_session_key(cli, session_key);
143 return NT_STATUS_OK;
146 /****************************************************************************
147 Work out suitable capabilities to offer the server.
148 ****************************************************************************/
150 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
152 uint32 capabilities = CAP_NT_SMBS;
154 if (!cli->force_dos_errors)
155 capabilities |= CAP_STATUS32;
157 if (cli->use_level_II_oplocks)
158 capabilities |= CAP_LEVEL_II_OPLOCKS;
160 capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
161 return capabilities;
164 /****************************************************************************
165 Do a NT1 guest session setup.
166 ****************************************************************************/
168 struct async_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
169 struct event_context *ev,
170 struct cli_state *cli)
172 struct async_req *result;
173 uint16_t vwv[13];
174 uint8_t *bytes;
176 SCVAL(vwv+0, 0, 0xFF);
177 SCVAL(vwv+0, 1, 0);
178 SSVAL(vwv+1, 0, 0);
179 SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
180 SSVAL(vwv+3, 0, 2);
181 SSVAL(vwv+4, 0, cli->pid);
182 SIVAL(vwv+5, 0, cli->sesskey);
183 SSVAL(vwv+7, 0, 0);
184 SSVAL(vwv+8, 0, 0);
185 SSVAL(vwv+9, 0, 0);
186 SSVAL(vwv+10, 0, 0);
187 SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli));
189 bytes = talloc_array(talloc_tos(), uint8_t, 0);
191 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* username */
192 NULL);
193 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
194 NULL);
195 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
196 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
198 if (bytes == NULL) {
199 return NULL;
202 result = cli_request_send(mem_ctx, ev, cli, SMBsesssetupX, 0,
203 13, vwv, 0, talloc_get_size(bytes), bytes);
204 TALLOC_FREE(bytes);
205 return result;
208 NTSTATUS cli_session_setup_guest_recv(struct async_req *req)
210 struct cli_request *cli_req = talloc_get_type_abort(
211 req->private_data, struct cli_request);
212 struct cli_state *cli = cli_req->cli;
213 uint8_t wct;
214 uint16_t *vwv;
215 uint16_t num_bytes;
216 uint8_t *bytes;
217 uint8_t *p;
218 NTSTATUS status;
220 if (async_req_is_nterror(req, &status)) {
221 return status;
224 status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
225 if (!NT_STATUS_IS_OK(status)) {
226 return status;
229 p = bytes;
231 cli->vuid = SVAL(cli_req->inbuf, smb_uid);
233 p += clistr_pull(cli_req->inbuf, cli->server_os, (char *)p,
234 sizeof(fstring), bytes+num_bytes-p, STR_TERMINATE);
235 p += clistr_pull(cli_req->inbuf, cli->server_type, (char *)p,
236 sizeof(fstring), bytes+num_bytes-p, STR_TERMINATE);
237 p += clistr_pull(cli_req->inbuf, cli->server_domain, (char *)p,
238 sizeof(fstring), bytes+num_bytes-p, STR_TERMINATE);
240 if (strstr(cli->server_type, "Samba")) {
241 cli->is_samba = True;
244 status = cli_set_username(cli, "");
245 if (!NT_STATUS_IS_OK(status)) {
246 return status;
249 return NT_STATUS_OK;
252 static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
254 TALLOC_CTX *frame = talloc_stackframe();
255 struct event_context *ev;
256 struct async_req *req;
257 NTSTATUS status;
259 if (cli->fd_event != NULL) {
261 * Can't use sync call while an async call is in flight
263 status = NT_STATUS_INVALID_PARAMETER;
264 goto fail;
267 ev = event_context_init(frame);
268 if (ev == NULL) {
269 status = NT_STATUS_NO_MEMORY;
270 goto fail;
273 req = cli_session_setup_guest_send(frame, ev, cli);
274 if (req == NULL) {
275 status = NT_STATUS_NO_MEMORY;
276 goto fail;
279 while (req->state < ASYNC_REQ_DONE) {
280 event_loop_once(ev);
283 status = cli_session_setup_guest_recv(req);
284 fail:
285 TALLOC_FREE(frame);
286 return status;
289 /****************************************************************************
290 Do a NT1 plaintext session setup.
291 ****************************************************************************/
293 static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
294 const char *user, const char *pass,
295 const char *workgroup)
297 uint32 capabilities = cli_session_setup_capabilities(cli);
298 char *p;
299 NTSTATUS status;
300 fstring lanman;
302 fstr_sprintf( lanman, "Samba %s", samba_version_string());
304 memset(cli->outbuf, '\0', smb_size);
305 cli_set_message(cli->outbuf,13,0,True);
306 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
307 cli_setup_packet(cli);
309 SCVAL(cli->outbuf,smb_vwv0,0xFF);
310 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
311 SSVAL(cli->outbuf,smb_vwv3,2);
312 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
313 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
314 SSVAL(cli->outbuf,smb_vwv8,0);
315 SIVAL(cli->outbuf,smb_vwv11,capabilities);
316 p = smb_buf(cli->outbuf);
318 /* check wether to send the ASCII or UNICODE version of the password */
320 if ( (capabilities & CAP_UNICODE) == 0 ) {
321 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
322 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
324 else {
325 /* For ucs2 passwords clistr_push calls ucs2_align, which causes
326 * the space taken by the unicode password to be one byte too
327 * long (as we're on an odd byte boundary here). Reduce the
328 * count by 1 to cope with this. Fixes smbclient against NetApp
329 * servers which can't cope. Fix from
330 * bryan.kolodziej@allenlund.com in bug #3840.
332 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
333 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);
336 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
337 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
338 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
339 p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
340 cli_setup_bcc(cli, p);
342 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
343 return cli_nt_error(cli);
346 show_msg(cli->inbuf);
348 if (cli_is_error(cli)) {
349 return cli_nt_error(cli);
352 cli->vuid = SVAL(cli->inbuf,smb_uid);
353 p = smb_buf(cli->inbuf);
354 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
355 -1, STR_TERMINATE);
356 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
357 -1, STR_TERMINATE);
358 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
359 -1, STR_TERMINATE);
360 status = cli_set_username(cli, user);
361 if (!NT_STATUS_IS_OK(status)) {
362 return status;
364 if (strstr(cli->server_type, "Samba")) {
365 cli->is_samba = True;
368 return NT_STATUS_OK;
371 /****************************************************************************
372 do a NT1 NTLM/LM encrypted session setup - for when extended security
373 is not negotiated.
374 @param cli client state to create do session setup on
375 @param user username
376 @param pass *either* cleartext password (passlen !=24) or LM response.
377 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
378 @param workgroup The user's domain.
379 ****************************************************************************/
381 static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user,
382 const char *pass, size_t passlen,
383 const char *ntpass, size_t ntpasslen,
384 const char *workgroup)
386 uint32 capabilities = cli_session_setup_capabilities(cli);
387 DATA_BLOB lm_response = data_blob_null;
388 DATA_BLOB nt_response = data_blob_null;
389 DATA_BLOB session_key = data_blob_null;
390 NTSTATUS result;
391 char *p;
392 bool ok;
394 if (passlen == 0) {
395 /* do nothing - guest login */
396 } else if (passlen != 24) {
397 if (lp_client_ntlmv2_auth()) {
398 DATA_BLOB server_chal;
399 DATA_BLOB names_blob;
400 server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8));
402 /* note that the 'workgroup' here is a best guess - we don't know
403 the server's domain at this point. The 'server name' is also
404 dodgy...
406 names_blob = NTLMv2_generate_names_blob(cli->called.name, workgroup);
408 if (!SMBNTLMv2encrypt(user, workgroup, pass, &server_chal,
409 &names_blob,
410 &lm_response, &nt_response, &session_key)) {
411 data_blob_free(&names_blob);
412 data_blob_free(&server_chal);
413 return NT_STATUS_ACCESS_DENIED;
415 data_blob_free(&names_blob);
416 data_blob_free(&server_chal);
418 } else {
419 uchar nt_hash[16];
420 E_md4hash(pass, nt_hash);
422 #ifdef LANMAN_ONLY
423 nt_response = data_blob_null;
424 #else
425 nt_response = data_blob(NULL, 24);
426 SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
427 #endif
428 /* non encrypted password supplied. Ignore ntpass. */
429 if (lp_client_lanman_auth()) {
430 lm_response = data_blob(NULL, 24);
431 if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
432 /* Oops, the LM response is invalid, just put
433 the NT response there instead */
434 data_blob_free(&lm_response);
435 lm_response = data_blob(nt_response.data, nt_response.length);
437 } else {
438 /* LM disabled, place NT# in LM field instead */
439 lm_response = data_blob(nt_response.data, nt_response.length);
442 session_key = data_blob(NULL, 16);
443 #ifdef LANMAN_ONLY
444 E_deshash(pass, session_key.data);
445 memset(&session_key.data[8], '\0', 8);
446 #else
447 SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
448 #endif
450 cli_temp_set_signing(cli);
451 } else {
452 /* pre-encrypted password supplied. Only used for
453 security=server, can't do
454 signing because we don't have original key */
456 lm_response = data_blob(pass, passlen);
457 nt_response = data_blob(ntpass, ntpasslen);
460 /* send a session setup command */
461 memset(cli->outbuf,'\0',smb_size);
463 cli_set_message(cli->outbuf,13,0,True);
464 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
465 cli_setup_packet(cli);
467 SCVAL(cli->outbuf,smb_vwv0,0xFF);
468 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
469 SSVAL(cli->outbuf,smb_vwv3,2);
470 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
471 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
472 SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
473 SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
474 SIVAL(cli->outbuf,smb_vwv11,capabilities);
475 p = smb_buf(cli->outbuf);
476 if (lm_response.length) {
477 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
479 if (nt_response.length) {
480 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
482 p += clistr_push(cli, p, user, -1, STR_TERMINATE);
484 /* Upper case here might help some NTLMv2 implementations */
485 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
486 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
487 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
488 cli_setup_bcc(cli, p);
490 if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
491 result = cli_nt_error(cli);
492 goto end;
495 /* show_msg(cli->inbuf); */
497 if (cli_is_error(cli)) {
498 result = cli_nt_error(cli);
499 goto end;
502 #ifdef LANMAN_ONLY
503 ok = cli_simple_set_signing(cli, session_key, lm_response);
504 #else
505 ok = cli_simple_set_signing(cli, session_key, nt_response);
506 #endif
507 if (ok) {
508 /* 'resign' the last message, so we get the right sequence numbers
509 for checking the first reply from the server */
510 cli_calculate_sign_mac(cli, cli->outbuf);
512 if (!cli_check_sign_mac(cli, cli->inbuf)) {
513 result = NT_STATUS_ACCESS_DENIED;
514 goto end;
518 /* use the returned vuid from now on */
519 cli->vuid = SVAL(cli->inbuf,smb_uid);
521 p = smb_buf(cli->inbuf);
522 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
523 -1, STR_TERMINATE);
524 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
525 -1, STR_TERMINATE);
526 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
527 -1, STR_TERMINATE);
529 if (strstr(cli->server_type, "Samba")) {
530 cli->is_samba = True;
533 result = cli_set_username(cli, user);
534 if (!NT_STATUS_IS_OK(result)) {
535 goto end;
538 if (session_key.data) {
539 /* Have plaintext orginal */
540 cli_set_session_key(cli, session_key);
543 result = NT_STATUS_OK;
544 end:
545 data_blob_free(&lm_response);
546 data_blob_free(&nt_response);
547 data_blob_free(&session_key);
548 return result;
551 /****************************************************************************
552 Send a extended security session setup blob
553 ****************************************************************************/
555 static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
557 uint32 capabilities = cli_session_setup_capabilities(cli);
558 char *p;
560 capabilities |= CAP_EXTENDED_SECURITY;
562 /* send a session setup command */
563 memset(cli->outbuf,'\0',smb_size);
565 cli_set_message(cli->outbuf,12,0,True);
566 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
568 cli_setup_packet(cli);
570 SCVAL(cli->outbuf,smb_vwv0,0xFF);
571 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
572 SSVAL(cli->outbuf,smb_vwv3,2);
573 SSVAL(cli->outbuf,smb_vwv4,1);
574 SIVAL(cli->outbuf,smb_vwv5,0);
575 SSVAL(cli->outbuf,smb_vwv7,blob.length);
576 SIVAL(cli->outbuf,smb_vwv10,capabilities);
577 p = smb_buf(cli->outbuf);
578 memcpy(p, blob.data, blob.length);
579 p += blob.length;
580 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
581 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
582 cli_setup_bcc(cli, p);
583 return cli_send_smb(cli);
586 /****************************************************************************
587 Send a extended security session setup blob, returning a reply blob.
588 ****************************************************************************/
590 static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
592 DATA_BLOB blob2 = data_blob_null;
593 char *p;
594 size_t len;
596 if (!cli_receive_smb(cli))
597 return blob2;
599 show_msg(cli->inbuf);
601 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
602 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
603 return blob2;
606 /* use the returned vuid from now on */
607 cli->vuid = SVAL(cli->inbuf,smb_uid);
609 p = smb_buf(cli->inbuf);
611 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
613 p += blob2.length;
614 p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
615 -1, STR_TERMINATE);
617 /* w2k with kerberos doesn't properly null terminate this field */
618 len = smb_bufrem(cli->inbuf, p);
619 if (p + len < cli->inbuf + cli->bufsize+SAFETY_MARGIN - 2) {
620 char *end_of_buf = p + len;
622 SSVAL(p, len, 0);
623 /* Now it's null terminated. */
624 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
625 -1, STR_TERMINATE);
627 * See if there's another string. If so it's the
628 * server domain (part of the 'standard' Samba
629 * server signature).
631 if (p < end_of_buf) {
632 p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
633 -1, STR_TERMINATE);
635 } else {
637 * No room to null terminate so we can't see if there
638 * is another string (server_domain) afterwards.
640 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
641 len, 0);
643 return blob2;
646 #ifdef HAVE_KRB5
647 /****************************************************************************
648 Send a extended security session setup blob, returning a reply blob.
649 ****************************************************************************/
651 /* The following is calculated from :
652 * (smb_size-4) = 35
653 * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
654 * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
655 * end of packet.
658 #define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
660 static bool cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
662 int32 remaining = blob.length;
663 int32 cur = 0;
664 DATA_BLOB send_blob = data_blob_null;
665 int32 max_blob_size = 0;
666 DATA_BLOB receive_blob = data_blob_null;
668 if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
669 DEBUG(0,("cli_session_setup_blob: cli->max_xmit too small "
670 "(was %u, need minimum %u)\n",
671 (unsigned int)cli->max_xmit,
672 BASE_SESSSETUP_BLOB_PACKET_SIZE));
673 cli_set_nt_error(cli, NT_STATUS_INVALID_PARAMETER);
674 return False;
677 max_blob_size = cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE;
679 while ( remaining > 0) {
680 if (remaining >= max_blob_size) {
681 send_blob.length = max_blob_size;
682 remaining -= max_blob_size;
683 } else {
684 send_blob.length = remaining;
685 remaining = 0;
688 send_blob.data = &blob.data[cur];
689 cur += send_blob.length;
691 DEBUG(10, ("cli_session_setup_blob: Remaining (%u) sending (%u) current (%u)\n",
692 (unsigned int)remaining,
693 (unsigned int)send_blob.length,
694 (unsigned int)cur ));
696 if (!cli_session_setup_blob_send(cli, send_blob)) {
697 DEBUG(0, ("cli_session_setup_blob: send failed\n"));
698 return False;
701 receive_blob = cli_session_setup_blob_receive(cli);
702 data_blob_free(&receive_blob);
704 if (cli_is_error(cli) &&
705 !NT_STATUS_EQUAL( cli_get_nt_error(cli),
706 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
707 DEBUG(0, ("cli_session_setup_blob: receive failed "
708 "(%s)\n", nt_errstr(cli_get_nt_error(cli))));
709 cli->vuid = 0;
710 return False;
714 return True;
717 /****************************************************************************
718 Use in-memory credentials cache
719 ****************************************************************************/
721 static void use_in_memory_ccache(void) {
722 setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
725 /****************************************************************************
726 Do a spnego/kerberos encrypted session setup.
727 ****************************************************************************/
729 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli, const char *principal, const char *workgroup)
731 DATA_BLOB negTokenTarg;
732 DATA_BLOB session_key_krb5;
733 NTSTATUS nt_status;
734 int rc;
736 cli_temp_set_signing(cli);
738 DEBUG(2,("Doing kerberos session setup\n"));
740 /* generate the encapsulated kerberos5 ticket */
741 rc = spnego_gen_negTokenTarg(principal, 0, &negTokenTarg, &session_key_krb5, 0, NULL);
743 if (rc) {
744 DEBUG(1, ("cli_session_setup_kerberos: spnego_gen_negTokenTarg failed: %s\n",
745 error_message(rc)));
746 return ADS_ERROR_KRB5(rc);
749 #if 0
750 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
751 #endif
753 if (!cli_session_setup_blob(cli, negTokenTarg)) {
754 nt_status = cli_nt_error(cli);
755 goto nt_error;
758 if (cli_is_error(cli)) {
759 nt_status = cli_nt_error(cli);
760 if (NT_STATUS_IS_OK(nt_status)) {
761 nt_status = NT_STATUS_UNSUCCESSFUL;
763 goto nt_error;
766 cli_set_session_key(cli, session_key_krb5);
768 if (cli_simple_set_signing(
769 cli, session_key_krb5, data_blob_null)) {
771 /* 'resign' the last message, so we get the right sequence numbers
772 for checking the first reply from the server */
773 cli_calculate_sign_mac(cli, cli->outbuf);
775 if (!cli_check_sign_mac(cli, cli->inbuf)) {
776 nt_status = NT_STATUS_ACCESS_DENIED;
777 goto nt_error;
781 data_blob_free(&negTokenTarg);
782 data_blob_free(&session_key_krb5);
784 return ADS_ERROR_NT(NT_STATUS_OK);
786 nt_error:
787 data_blob_free(&negTokenTarg);
788 data_blob_free(&session_key_krb5);
789 cli->vuid = 0;
790 return ADS_ERROR_NT(nt_status);
792 #endif /* HAVE_KRB5 */
795 /****************************************************************************
796 Do a spnego/NTLMSSP encrypted session setup.
797 ****************************************************************************/
799 static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
800 const char *pass, const char *domain)
802 struct ntlmssp_state *ntlmssp_state;
803 NTSTATUS nt_status;
804 int turn = 1;
805 DATA_BLOB msg1;
806 DATA_BLOB blob = data_blob_null;
807 DATA_BLOB blob_in = data_blob_null;
808 DATA_BLOB blob_out = data_blob_null;
810 cli_temp_set_signing(cli);
812 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
813 return nt_status;
815 ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
817 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
818 return nt_status;
820 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
821 return nt_status;
823 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, pass))) {
824 return nt_status;
827 do {
828 nt_status = ntlmssp_update(ntlmssp_state,
829 blob_in, &blob_out);
830 data_blob_free(&blob_in);
831 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) || NT_STATUS_IS_OK(nt_status)) {
832 if (turn == 1) {
833 /* and wrap it in a SPNEGO wrapper */
834 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
835 } else {
836 /* wrap it in SPNEGO */
837 msg1 = spnego_gen_auth(blob_out);
840 /* now send that blob on its way */
841 if (!cli_session_setup_blob_send(cli, msg1)) {
842 DEBUG(3, ("Failed to send NTLMSSP/SPNEGO blob to server!\n"));
843 nt_status = NT_STATUS_UNSUCCESSFUL;
844 } else {
845 blob = cli_session_setup_blob_receive(cli);
847 nt_status = cli_nt_error(cli);
848 if (cli_is_error(cli) && NT_STATUS_IS_OK(nt_status)) {
849 if (cli->smb_rw_error == SMB_READ_BAD_SIG) {
850 nt_status = NT_STATUS_ACCESS_DENIED;
851 } else {
852 nt_status = NT_STATUS_UNSUCCESSFUL;
856 data_blob_free(&msg1);
859 if (!blob.length) {
860 if (NT_STATUS_IS_OK(nt_status)) {
861 nt_status = NT_STATUS_UNSUCCESSFUL;
863 } else if ((turn == 1) &&
864 NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
865 DATA_BLOB tmp_blob = data_blob_null;
866 /* the server might give us back two challenges */
867 if (!spnego_parse_challenge(blob, &blob_in,
868 &tmp_blob)) {
869 DEBUG(3,("Failed to parse challenges\n"));
870 nt_status = NT_STATUS_INVALID_PARAMETER;
872 data_blob_free(&tmp_blob);
873 } else {
874 if (!spnego_parse_auth_response(blob, nt_status, OID_NTLMSSP,
875 &blob_in)) {
876 DEBUG(3,("Failed to parse auth response\n"));
877 if (NT_STATUS_IS_OK(nt_status)
878 || NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED))
879 nt_status = NT_STATUS_INVALID_PARAMETER;
882 data_blob_free(&blob);
883 data_blob_free(&blob_out);
884 turn++;
885 } while (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED));
887 data_blob_free(&blob_in);
889 if (NT_STATUS_IS_OK(nt_status)) {
891 if (cli->server_domain[0] == '\0') {
892 fstrcpy(cli->server_domain, ntlmssp_state->server_domain);
894 cli_set_session_key(cli, ntlmssp_state->session_key);
896 if (cli_simple_set_signing(
897 cli, ntlmssp_state->session_key, data_blob_null)) {
899 /* 'resign' the last message, so we get the right sequence numbers
900 for checking the first reply from the server */
901 cli_calculate_sign_mac(cli, cli->outbuf);
903 if (!cli_check_sign_mac(cli, cli->inbuf)) {
904 nt_status = NT_STATUS_ACCESS_DENIED;
909 /* we have a reference conter on ntlmssp_state, if we are signing
910 then the state will be kept by the signing engine */
912 ntlmssp_end(&ntlmssp_state);
914 if (!NT_STATUS_IS_OK(nt_status)) {
915 cli->vuid = 0;
917 return nt_status;
920 /****************************************************************************
921 Do a spnego encrypted session setup.
923 user_domain: The shortname of the domain the user/machine is a member of.
924 dest_realm: The realm we're connecting to, if NULL we use our default realm.
925 ****************************************************************************/
927 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
928 const char *pass, const char *user_domain,
929 const char * dest_realm)
931 char *principal = NULL;
932 char *OIDs[ASN1_MAX_OIDS];
933 int i;
934 DATA_BLOB blob;
935 const char *p = NULL;
936 char *account = NULL;
937 NTSTATUS status;
939 DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
941 /* the server might not even do spnego */
942 if (cli->secblob.length <= 16) {
943 DEBUG(3,("server didn't supply a full spnego negprot\n"));
944 goto ntlmssp;
947 #if 0
948 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
949 #endif
951 /* there is 16 bytes of GUID before the real spnego packet starts */
952 blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
954 /* The server sent us the first part of the SPNEGO exchange in the
955 * negprot reply. It is WRONG to depend on the principal sent in the
956 * negprot reply, but right now we do it. If we don't receive one,
957 * we try to best guess, then fall back to NTLM. */
958 if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
959 data_blob_free(&blob);
960 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
962 data_blob_free(&blob);
964 /* make sure the server understands kerberos */
965 for (i=0;OIDs[i];i++) {
966 DEBUG(3,("got OID=%s\n", OIDs[i]));
967 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
968 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
969 cli->got_kerberos_mechanism = True;
971 talloc_free(OIDs[i]);
974 DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
976 status = cli_set_username(cli, user);
977 if (!NT_STATUS_IS_OK(status)) {
978 return ADS_ERROR_NT(status);
981 #ifdef HAVE_KRB5
982 /* If password is set we reauthenticate to kerberos server
983 * and do not store results */
985 if (cli->got_kerberos_mechanism && cli->use_kerberos) {
986 ADS_STATUS rc;
988 if (pass && *pass) {
989 int ret;
991 use_in_memory_ccache();
992 ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
994 if (ret){
995 TALLOC_FREE(principal);
996 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
997 if (cli->fallback_after_kerberos)
998 goto ntlmssp;
999 return ADS_ERROR_KRB5(ret);
1003 /* If we get a bad principal, try to guess it if
1004 we have a valid host NetBIOS name.
1006 if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1007 TALLOC_FREE(principal);
1010 if (principal == NULL &&
1011 !is_ipaddress(cli->desthost) &&
1012 !strequal(STAR_SMBSERVER,
1013 cli->desthost)) {
1014 char *realm = NULL;
1015 char *machine = NULL;
1016 char *host = NULL;
1017 DEBUG(3,("cli_session_setup_spnego: got a "
1018 "bad server principal, trying to guess ...\n"));
1020 host = strchr_m(cli->desthost, '.');
1021 if (host) {
1022 machine = SMB_STRNDUP(cli->desthost,
1023 host - cli->desthost);
1024 } else {
1025 machine = SMB_STRDUP(cli->desthost);
1027 if (machine == NULL) {
1028 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1031 if (dest_realm) {
1032 realm = SMB_STRDUP(dest_realm);
1033 strupper_m(realm);
1034 } else {
1035 realm = kerberos_get_default_realm_from_ccache();
1037 if (realm && *realm) {
1038 principal = talloc_asprintf(NULL, "%s$@%s",
1039 machine, realm);
1040 if (!principal) {
1041 SAFE_FREE(machine);
1042 SAFE_FREE(realm);
1043 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1045 DEBUG(3,("cli_session_setup_spnego: guessed "
1046 "server principal=%s\n",
1047 principal ? principal : "<null>"));
1049 SAFE_FREE(machine);
1050 SAFE_FREE(realm);
1053 if (principal) {
1054 rc = cli_session_setup_kerberos(cli, principal,
1055 dest_realm);
1056 if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
1057 TALLOC_FREE(principal);
1058 return rc;
1062 #endif
1064 TALLOC_FREE(principal);
1066 ntlmssp:
1068 account = talloc_strdup(talloc_tos(), user);
1069 if (!account) {
1070 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1073 /* when falling back to ntlmssp while authenticating with a machine
1074 * account strip off the realm - gd */
1076 if ((p = strchr_m(user, '@')) != NULL) {
1077 account[PTR_DIFF(p,user)] = '\0';
1080 return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
1083 /****************************************************************************
1084 Send a session setup. The username and workgroup is in UNIX character
1085 format and must be converted to DOS codepage format before sending. If the
1086 password is in plaintext, the same should be done.
1087 ****************************************************************************/
1089 NTSTATUS cli_session_setup(struct cli_state *cli,
1090 const char *user,
1091 const char *pass, int passlen,
1092 const char *ntpass, int ntpasslen,
1093 const char *workgroup)
1095 char *p;
1096 fstring user2;
1098 if (user) {
1099 fstrcpy(user2, user);
1100 } else {
1101 user2[0] ='\0';
1104 if (!workgroup) {
1105 workgroup = "";
1108 /* allow for workgroups as part of the username */
1109 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
1110 (p=strchr_m(user2,*lp_winbind_separator()))) {
1111 *p = 0;
1112 user = p+1;
1113 workgroup = user2;
1116 if (cli->protocol < PROTOCOL_LANMAN1) {
1117 return NT_STATUS_OK;
1120 /* now work out what sort of session setup we are going to
1121 do. I have split this into separate functions to make the
1122 flow a bit easier to understand (tridge) */
1124 /* if its an older server then we have to use the older request format */
1126 if (cli->protocol < PROTOCOL_NT1) {
1127 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
1128 DEBUG(1, ("Server requested LM password but 'client lanman auth'"
1129 " is disabled\n"));
1130 return NT_STATUS_ACCESS_DENIED;
1133 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
1134 !lp_client_plaintext_auth() && (*pass)) {
1135 DEBUG(1, ("Server requested plaintext password but "
1136 "'client plaintext auth' is disabled\n"));
1137 return NT_STATUS_ACCESS_DENIED;
1140 return cli_session_setup_lanman2(cli, user, pass, passlen,
1141 workgroup);
1144 /* if no user is supplied then we have to do an anonymous connection.
1145 passwords are ignored */
1147 if (!user || !*user)
1148 return cli_session_setup_guest(cli);
1150 /* if the server is share level then send a plaintext null
1151 password at this point. The password is sent in the tree
1152 connect */
1154 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0)
1155 return cli_session_setup_plaintext(cli, user, "", workgroup);
1157 /* if the server doesn't support encryption then we have to use
1158 plaintext. The second password is ignored */
1160 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
1161 if (!lp_client_plaintext_auth() && (*pass)) {
1162 DEBUG(1, ("Server requested plaintext password but "
1163 "'client plaintext auth' is disabled\n"));
1164 return NT_STATUS_ACCESS_DENIED;
1166 return cli_session_setup_plaintext(cli, user, pass, workgroup);
1169 /* if the server supports extended security then use SPNEGO */
1171 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
1172 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
1173 workgroup, NULL);
1174 if (!ADS_ERR_OK(status)) {
1175 DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
1176 return ads_ntstatus(status);
1178 } else {
1179 NTSTATUS status;
1181 /* otherwise do a NT1 style session setup */
1182 status = cli_session_setup_nt1(cli, user, pass, passlen,
1183 ntpass, ntpasslen, workgroup);
1184 if (!NT_STATUS_IS_OK(status)) {
1185 DEBUG(3,("cli_session_setup: NT1 session setup "
1186 "failed: %s\n", nt_errstr(status)));
1187 return status;
1191 if (strstr(cli->server_type, "Samba")) {
1192 cli->is_samba = True;
1195 return NT_STATUS_OK;
1198 /****************************************************************************
1199 Send a uloggoff.
1200 *****************************************************************************/
1202 bool cli_ulogoff(struct cli_state *cli)
1204 memset(cli->outbuf,'\0',smb_size);
1205 cli_set_message(cli->outbuf,2,0,True);
1206 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
1207 cli_setup_packet(cli);
1208 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1209 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1211 cli_send_smb(cli);
1212 if (!cli_receive_smb(cli))
1213 return False;
1215 if (cli_is_error(cli)) {
1216 return False;
1219 cli->vuid = -1;
1220 return True;
1223 /****************************************************************************
1224 Send a tconX.
1225 ****************************************************************************/
1227 struct async_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
1228 struct event_context *ev,
1229 struct cli_state *cli,
1230 const char *share, const char *dev,
1231 const char *pass, int passlen)
1233 fstring pword;
1234 char *tmp = NULL;
1235 struct async_req *result;
1236 uint16_t vwv[4];
1237 uint8_t *bytes;
1239 fstrcpy(cli->share, share);
1241 /* in user level security don't send a password now */
1242 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
1243 passlen = 1;
1244 pass = "";
1245 } else if (pass == NULL) {
1246 DEBUG(1, ("Server not using user level security and no "
1247 "password supplied.\n"));
1248 goto access_denied;
1251 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
1252 *pass && passlen != 24) {
1253 if (!lp_client_lanman_auth()) {
1254 DEBUG(1, ("Server requested LANMAN password "
1255 "(share-level security) but "
1256 "'client lanman auth' is disabled\n"));
1257 goto access_denied;
1261 * Non-encrypted passwords - convert to DOS codepage before
1262 * encryption.
1264 passlen = 24;
1265 SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
1266 } else {
1267 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
1268 |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
1269 == 0) {
1270 if (!lp_client_plaintext_auth() && (*pass)) {
1271 DEBUG(1, ("Server requested plaintext "
1272 "password but 'client plaintext "
1273 "auth' is disabled\n"));
1274 goto access_denied;
1278 * Non-encrypted passwords - convert to DOS codepage
1279 * before using.
1281 passlen = clistr_push(cli, pword, pass, sizeof(pword),
1282 STR_TERMINATE);
1283 if (passlen == -1) {
1284 DEBUG(1, ("clistr_push(pword) failed\n"));
1285 goto access_denied;
1287 } else {
1288 if (passlen) {
1289 memcpy(pword, pass, passlen);
1294 SCVAL(vwv+0, 0, 0xFF);
1295 SCVAL(vwv+0, 1, 0);
1296 SSVAL(vwv+1, 0, 0);
1297 SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
1298 SSVAL(vwv+3, 0, passlen);
1300 if (passlen) {
1301 bytes = (uint8_t *)talloc_memdup(talloc_tos(), pword, passlen);
1302 } else {
1303 bytes = talloc_array(talloc_tos(), uint8_t, 0);
1307 * Add the sharename
1309 tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
1310 cli->desthost, share);
1311 if (tmp == NULL) {
1312 TALLOC_FREE(bytes);
1313 return NULL;
1315 bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
1316 NULL);
1317 TALLOC_FREE(tmp);
1320 * Add the devicetype
1322 tmp = talloc_strdup_upper(talloc_tos(), dev);
1323 if (tmp == NULL) {
1324 TALLOC_FREE(bytes);
1325 return NULL;
1327 bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
1328 TALLOC_FREE(tmp);
1330 if (bytes == NULL) {
1331 return NULL;
1334 result = cli_request_send(mem_ctx, ev, cli, SMBtconX, 0,
1335 4, vwv, 0, talloc_get_size(bytes), bytes);
1336 TALLOC_FREE(bytes);
1337 return result;
1339 access_denied:
1341 struct cli_request *state;
1342 if (!async_req_setup(mem_ctx, &result, &state,
1343 struct cli_request)) {
1344 goto fail;
1346 if (async_post_ntstatus(result, ev, NT_STATUS_ACCESS_DENIED)) {
1347 return result;
1350 fail:
1351 TALLOC_FREE(result);
1352 return NULL;
1355 NTSTATUS cli_tcon_andx_recv(struct async_req *req)
1357 struct cli_request *cli_req = talloc_get_type_abort(
1358 req->private_data, struct cli_request);
1359 struct cli_state *cli = cli_req->cli;
1360 uint8_t wct;
1361 uint16_t *vwv;
1362 uint16_t num_bytes;
1363 uint8_t *bytes;
1364 NTSTATUS status;
1366 if (async_req_is_nterror(req, &status)) {
1367 return status;
1370 status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
1371 if (!NT_STATUS_IS_OK(status)) {
1372 return status;
1375 clistr_pull(cli_req->inbuf, cli->dev, bytes, sizeof(fstring),
1376 num_bytes, STR_TERMINATE|STR_ASCII);
1378 if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
1379 /* almost certainly win95 - enable bug fixes */
1380 cli->win95 = True;
1384 * Make sure that we have the optional support 16-bit field. WCT > 2.
1385 * Avoids issues when connecting to Win9x boxes sharing files
1388 cli->dfsroot = false;
1390 if ((wct > 2) && (cli->protocol >= PROTOCOL_LANMAN2)) {
1391 cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
1394 cli->cnum = SVAL(cli_req->inbuf,smb_tid);
1395 return NT_STATUS_OK;
1398 NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
1399 const char *dev, const char *pass, int passlen)
1401 TALLOC_CTX *frame = talloc_stackframe();
1402 struct event_context *ev;
1403 struct async_req *req;
1404 NTSTATUS status;
1406 if (cli->fd_event != NULL) {
1408 * Can't use sync call while an async call is in flight
1410 status = NT_STATUS_INVALID_PARAMETER;
1411 goto fail;
1414 ev = event_context_init(frame);
1415 if (ev == NULL) {
1416 status = NT_STATUS_NO_MEMORY;
1417 goto fail;
1420 req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
1421 if (req == NULL) {
1422 status = NT_STATUS_NO_MEMORY;
1423 goto fail;
1426 while (req->state < ASYNC_REQ_DONE) {
1427 event_loop_once(ev);
1430 status = cli_tcon_andx_recv(req);
1431 fail:
1432 TALLOC_FREE(frame);
1433 return status;
1436 /****************************************************************************
1437 Send a tree disconnect.
1438 ****************************************************************************/
1440 bool cli_tdis(struct cli_state *cli)
1442 memset(cli->outbuf,'\0',smb_size);
1443 cli_set_message(cli->outbuf,0,0,True);
1444 SCVAL(cli->outbuf,smb_com,SMBtdis);
1445 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1446 cli_setup_packet(cli);
1448 cli_send_smb(cli);
1449 if (!cli_receive_smb(cli))
1450 return False;
1452 if (cli_is_error(cli)) {
1453 return False;
1456 cli->cnum = -1;
1457 return True;
1460 /****************************************************************************
1461 Send a negprot command.
1462 ****************************************************************************/
1464 void cli_negprot_sendsync(struct cli_state *cli)
1466 char *p;
1467 int numprots;
1469 if (cli->protocol < PROTOCOL_NT1)
1470 cli->use_spnego = False;
1472 memset(cli->outbuf,'\0',smb_size);
1474 /* setup the protocol strings */
1475 cli_set_message(cli->outbuf,0,0,True);
1477 p = smb_buf(cli->outbuf);
1478 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1479 if (prots[numprots].prot > cli->protocol) {
1480 break;
1482 *p++ = 2;
1483 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1486 SCVAL(cli->outbuf,smb_com,SMBnegprot);
1487 cli_setup_bcc(cli, p);
1488 cli_setup_packet(cli);
1490 SCVAL(smb_buf(cli->outbuf),0,2);
1492 cli_send_smb(cli);
1495 /****************************************************************************
1496 Send a negprot command.
1497 ****************************************************************************/
1499 struct async_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
1500 struct event_context *ev,
1501 struct cli_state *cli)
1503 struct async_req *result;
1504 uint8_t *bytes = NULL;
1505 int numprots;
1507 if (cli->protocol < PROTOCOL_NT1)
1508 cli->use_spnego = False;
1510 /* setup the protocol strings */
1511 for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1512 uint8_t c = 2;
1513 if (prots[numprots].prot > cli->protocol) {
1514 break;
1516 bytes = (uint8_t *)talloc_append_blob(
1517 talloc_tos(), bytes, data_blob_const(&c, sizeof(c)));
1518 if (bytes == NULL) {
1519 return NULL;
1521 bytes = smb_bytes_push_str(bytes, false,
1522 prots[numprots].name,
1523 strlen(prots[numprots].name)+1,
1524 NULL);
1525 if (bytes == NULL) {
1526 return NULL;
1530 result = cli_request_send(mem_ctx, ev, cli, SMBnegprot, 0, 0, NULL, 0,
1531 talloc_get_size(bytes), bytes);
1532 TALLOC_FREE(bytes);
1533 return result;
1536 NTSTATUS cli_negprot_recv(struct async_req *req)
1538 struct cli_request *cli_req = talloc_get_type_abort(
1539 req->private_data, struct cli_request);
1540 struct cli_state *cli = cli_req->cli;
1541 uint8_t wct;
1542 uint16_t *vwv;
1543 uint16_t num_bytes;
1544 uint8_t *bytes;
1545 NTSTATUS status;
1546 uint16_t protnum;
1548 if (async_req_is_nterror(req, &status)) {
1549 return status;
1552 status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes);
1553 if (!NT_STATUS_IS_OK(status)) {
1554 return status;
1557 protnum = SVAL(vwv, 0);
1559 if ((protnum >= ARRAY_SIZE(prots))
1560 || (prots[protnum].prot > cli_req->cli->protocol)) {
1561 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1564 cli->protocol = prots[protnum].prot;
1566 if ((cli->protocol < PROTOCOL_NT1) && cli->sign_info.mandatory_signing) {
1567 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
1568 return NT_STATUS_ACCESS_DENIED;
1571 if (cli->protocol >= PROTOCOL_NT1) {
1572 struct timespec ts;
1573 /* NT protocol */
1574 cli->sec_mode = CVAL(vwv + 1, 0);
1575 cli->max_mux = SVAL(vwv + 1, 1);
1576 cli->max_xmit = IVAL(vwv + 3, 1);
1577 cli->sesskey = IVAL(vwv + 7, 1);
1578 cli->serverzone = SVALS(vwv + 15, 1);
1579 cli->serverzone *= 60;
1580 /* this time arrives in real GMT */
1581 ts = interpret_long_date(((char *)(vwv+11))+1);
1582 cli->servertime = ts.tv_sec;
1583 cli->secblob = data_blob(bytes, num_bytes);
1584 cli->capabilities = IVAL(vwv + 9, 1);
1585 if (cli->capabilities & CAP_RAW_MODE) {
1586 cli->readbraw_supported = True;
1587 cli->writebraw_supported = True;
1589 /* work out if they sent us a workgroup */
1590 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
1591 smb_buflen(cli->inbuf) > 8) {
1592 clistr_pull(cli->inbuf, cli->server_domain,
1593 bytes+8, sizeof(cli->server_domain),
1594 num_bytes-8,
1595 STR_UNICODE|STR_NOALIGN);
1599 * As signing is slow we only turn it on if either the client or
1600 * the server require it. JRA.
1603 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
1604 /* Fail if server says signing is mandatory and we don't want to support it. */
1605 if (!cli->sign_info.allow_smb_signing) {
1606 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
1607 return NT_STATUS_ACCESS_DENIED;
1609 cli->sign_info.negotiated_smb_signing = True;
1610 cli->sign_info.mandatory_signing = True;
1611 } else if (cli->sign_info.mandatory_signing && cli->sign_info.allow_smb_signing) {
1612 /* Fail if client says signing is mandatory and the server doesn't support it. */
1613 if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
1614 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
1615 return NT_STATUS_ACCESS_DENIED;
1617 cli->sign_info.negotiated_smb_signing = True;
1618 cli->sign_info.mandatory_signing = True;
1619 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
1620 cli->sign_info.negotiated_smb_signing = True;
1623 if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
1624 SAFE_FREE(cli->outbuf);
1625 SAFE_FREE(cli->inbuf);
1626 cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
1627 cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
1628 cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
1631 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
1632 cli->use_spnego = False;
1633 cli->sec_mode = SVAL(vwv + 1, 0);
1634 cli->max_xmit = SVAL(vwv + 2, 0);
1635 cli->max_mux = SVAL(vwv + 3, 0);
1636 cli->sesskey = IVAL(vwv + 6, 0);
1637 cli->serverzone = SVALS(vwv + 10, 0);
1638 cli->serverzone *= 60;
1639 /* this time is converted to GMT by make_unix_date */
1640 cli->servertime = cli_make_unix_date(
1641 cli, (char *)(vwv + 8));
1642 cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0);
1643 cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0);
1644 cli->secblob = data_blob(bytes, num_bytes);
1645 } else {
1646 /* the old core protocol */
1647 cli->use_spnego = False;
1648 cli->sec_mode = 0;
1649 cli->serverzone = get_time_zone(time(NULL));
1652 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
1654 /* a way to force ascii SMB */
1655 if (getenv("CLI_FORCE_ASCII"))
1656 cli->capabilities &= ~CAP_UNICODE;
1658 return NT_STATUS_OK;
1661 NTSTATUS cli_negprot(struct cli_state *cli)
1663 TALLOC_CTX *frame = talloc_stackframe();
1664 struct event_context *ev;
1665 struct async_req *req;
1666 NTSTATUS status = NT_STATUS_NO_MEMORY;
1668 if (cli->fd_event != NULL) {
1670 * Can't use sync call while an async call is in flight
1672 cli_set_error(cli, NT_STATUS_INVALID_PARAMETER);
1673 goto fail;
1676 ev = event_context_init(frame);
1677 if (ev == NULL) {
1678 goto fail;
1681 req = cli_negprot_send(frame, ev, cli);
1682 if (req == NULL) {
1683 goto fail;
1686 while (req->state < ASYNC_REQ_DONE) {
1687 event_loop_once(ev);
1690 status = cli_negprot_recv(req);
1691 fail:
1692 TALLOC_FREE(frame);
1693 return status;
1696 /****************************************************************************
1697 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
1698 ****************************************************************************/
1700 bool cli_session_request(struct cli_state *cli,
1701 struct nmb_name *calling, struct nmb_name *called)
1703 char *p;
1704 int len = 4;
1705 char *tmp;
1707 /* 445 doesn't have session request */
1708 if (cli->port == 445)
1709 return True;
1711 memcpy(&(cli->calling), calling, sizeof(*calling));
1712 memcpy(&(cli->called ), called , sizeof(*called ));
1714 /* put in the destination name */
1716 tmp = name_mangle(talloc_tos(), cli->called.name,
1717 cli->called.name_type);
1718 if (tmp == NULL) {
1719 return false;
1722 p = cli->outbuf+len;
1723 memcpy(p, tmp, name_len(tmp));
1724 len += name_len(tmp);
1725 TALLOC_FREE(tmp);
1727 /* and my name */
1729 tmp = name_mangle(talloc_tos(), cli->calling.name,
1730 cli->calling.name_type);
1731 if (tmp == NULL) {
1732 return false;
1735 p = cli->outbuf+len;
1736 memcpy(p, tmp, name_len(tmp));
1737 len += name_len(tmp);
1738 TALLOC_FREE(tmp);
1740 /* send a session request (RFC 1002) */
1741 /* setup the packet length
1742 * Remove four bytes from the length count, since the length
1743 * field in the NBT Session Service header counts the number
1744 * of bytes which follow. The cli_send_smb() function knows
1745 * about this and accounts for those four bytes.
1746 * CRH.
1748 len -= 4;
1749 _smb_setlen(cli->outbuf,len);
1750 SCVAL(cli->outbuf,0,0x81);
1752 cli_send_smb(cli);
1753 DEBUG(5,("Sent session request\n"));
1755 if (!cli_receive_smb(cli))
1756 return False;
1758 if (CVAL(cli->inbuf,0) == 0x84) {
1759 /* C. Hoch 9/14/95 Start */
1760 /* For information, here is the response structure.
1761 * We do the byte-twiddling to for portability.
1762 struct RetargetResponse{
1763 unsigned char type;
1764 unsigned char flags;
1765 int16 length;
1766 int32 ip_addr;
1767 int16 port;
1770 uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
1771 struct in_addr dest_ip;
1772 NTSTATUS status;
1774 /* SESSION RETARGET */
1775 putip((char *)&dest_ip,cli->inbuf+4);
1776 in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
1778 status = open_socket_out(&cli->dest_ss, port,
1779 LONG_CONNECT_TIMEOUT, &cli->fd);
1780 if (!NT_STATUS_IS_OK(status)) {
1781 return False;
1784 DEBUG(3,("Retargeted\n"));
1786 set_socket_options(cli->fd, lp_socket_options());
1788 /* Try again */
1790 static int depth;
1791 bool ret;
1792 if (depth > 4) {
1793 DEBUG(0,("Retarget recursion - failing\n"));
1794 return False;
1796 depth++;
1797 ret = cli_session_request(cli, calling, called);
1798 depth--;
1799 return ret;
1801 } /* C. Hoch 9/14/95 End */
1803 if (CVAL(cli->inbuf,0) != 0x82) {
1804 /* This is the wrong place to put the error... JRA. */
1805 cli->rap_error = CVAL(cli->inbuf,4);
1806 return False;
1808 return(True);
1811 struct fd_struct {
1812 int fd;
1815 static void smb_sock_connected(struct tevent_req *req)
1817 struct fd_struct *pfd = tevent_req_callback_data(
1818 req, struct fd_struct);
1819 int fd;
1820 NTSTATUS status;
1822 status = open_socket_out_defer_recv(req, &fd);
1823 if (NT_STATUS_IS_OK(status)) {
1824 pfd->fd = fd;
1828 static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
1829 uint16_t *port, int timeout, int *pfd)
1831 struct event_context *ev;
1832 struct tevent_req *r139, *r445;
1833 struct fd_struct *fd139, *fd445;
1834 NTSTATUS status = NT_STATUS_NO_MEMORY;
1836 if (*port != 0) {
1837 return open_socket_out(pss, *port, timeout, pfd);
1840 ev = event_context_init(talloc_tos());
1841 if (ev == NULL) {
1842 return NT_STATUS_NO_MEMORY;
1845 fd139 = talloc(ev, struct fd_struct);
1846 if (fd139 == NULL) {
1847 goto done;
1849 fd139->fd = -1;
1851 fd445 = talloc(ev, struct fd_struct);
1852 if (fd445 == NULL) {
1853 goto done;
1855 fd445->fd = -1;
1857 r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
1858 pss, 445, timeout);
1859 r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
1860 pss, 139, timeout);
1861 if ((r445 == NULL) || (r139 == NULL)) {
1862 goto done;
1864 tevent_req_set_callback(r445, smb_sock_connected, fd445);
1865 tevent_req_set_callback(r139, smb_sock_connected, fd139);
1867 while ((fd445->fd == -1) && (fd139->fd == -1)
1868 && (tevent_req_is_in_progress(r139)
1869 || tevent_req_is_in_progress(r445))) {
1870 event_loop_once(ev);
1873 if ((fd139->fd != -1) && (fd445->fd != -1)) {
1874 close(fd139->fd);
1875 fd139->fd = -1;
1878 if (fd445->fd != -1) {
1879 *port = 445;
1880 *pfd = fd445->fd;
1881 status = NT_STATUS_OK;
1882 goto done;
1884 if (fd139->fd != -1) {
1885 *port = 139;
1886 *pfd = fd139->fd;
1887 status = NT_STATUS_OK;
1888 goto done;
1891 status = open_socket_out_defer_recv(r445, &fd445->fd);
1892 done:
1893 TALLOC_FREE(ev);
1894 return status;
1897 /****************************************************************************
1898 Open the client sockets.
1899 ****************************************************************************/
1901 NTSTATUS cli_connect(struct cli_state *cli,
1902 const char *host,
1903 struct sockaddr_storage *dest_ss)
1906 int name_type = 0x20;
1907 TALLOC_CTX *frame = talloc_stackframe();
1908 unsigned int num_addrs = 0;
1909 unsigned int i = 0;
1910 struct sockaddr_storage *ss_arr = NULL;
1911 char *p = NULL;
1913 /* reasonable default hostname */
1914 if (!host) {
1915 host = STAR_SMBSERVER;
1918 fstrcpy(cli->desthost, host);
1920 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1921 if ((p = strchr(cli->desthost, '#'))) {
1922 name_type = strtol(p+1, NULL, 16);
1923 *p = 0;
1926 if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
1927 NTSTATUS status =resolve_name_list(frame,
1928 cli->desthost,
1929 name_type,
1930 &ss_arr,
1931 &num_addrs);
1932 if (!NT_STATUS_IS_OK(status)) {
1933 TALLOC_FREE(frame);
1934 return NT_STATUS_BAD_NETWORK_NAME;
1936 } else {
1937 num_addrs = 1;
1938 ss_arr = TALLOC_P(frame, struct sockaddr_storage);
1939 if (!ss_arr) {
1940 TALLOC_FREE(frame);
1941 return NT_STATUS_NO_MEMORY;
1943 *ss_arr = *dest_ss;
1946 for (i = 0; i < num_addrs; i++) {
1947 cli->dest_ss = ss_arr[i];
1948 if (getenv("LIBSMB_PROG")) {
1949 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1950 } else {
1951 uint16_t port = cli->port;
1952 NTSTATUS status;
1953 status = open_smb_socket(&cli->dest_ss, &port,
1954 cli->timeout, &cli->fd);
1955 if (NT_STATUS_IS_OK(status)) {
1956 cli->port = port;
1959 if (cli->fd == -1) {
1960 char addr[INET6_ADDRSTRLEN];
1961 print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
1962 DEBUG(2,("Error connecting to %s (%s)\n",
1963 dest_ss?addr:host,strerror(errno)));
1964 } else {
1965 /* Exit from loop on first connection. */
1966 break;
1970 if (cli->fd == -1) {
1971 TALLOC_FREE(frame);
1972 return map_nt_error_from_unix(errno);
1975 if (dest_ss) {
1976 *dest_ss = cli->dest_ss;
1979 set_socket_options(cli->fd, lp_socket_options());
1981 TALLOC_FREE(frame);
1982 return NT_STATUS_OK;
1986 establishes a connection to after the negprot.
1987 @param output_cli A fully initialised cli structure, non-null only on success
1988 @param dest_host The netbios name of the remote host
1989 @param dest_ss (optional) The the destination IP, NULL for name based lookup
1990 @param port (optional) The destination port (0 for default)
1991 @param retry bool. Did this connection fail with a retryable error ?
1994 NTSTATUS cli_start_connection(struct cli_state **output_cli,
1995 const char *my_name,
1996 const char *dest_host,
1997 struct sockaddr_storage *dest_ss, int port,
1998 int signing_state, int flags,
1999 bool *retry)
2001 NTSTATUS nt_status;
2002 struct nmb_name calling;
2003 struct nmb_name called;
2004 struct cli_state *cli;
2005 struct sockaddr_storage ss;
2007 if (retry)
2008 *retry = False;
2010 if (!my_name)
2011 my_name = global_myname();
2013 if (!(cli = cli_initialise_ex(signing_state))) {
2014 return NT_STATUS_NO_MEMORY;
2017 make_nmb_name(&calling, my_name, 0x0);
2018 make_nmb_name(&called , dest_host, 0x20);
2020 cli_set_port(cli, port);
2021 cli_set_timeout(cli, 10000); /* 10 seconds. */
2023 if (dest_ss) {
2024 ss = *dest_ss;
2025 } else {
2026 zero_sockaddr(&ss);
2029 again:
2031 DEBUG(3,("Connecting to host=%s\n", dest_host));
2033 nt_status = cli_connect(cli, dest_host, &ss);
2034 if (!NT_STATUS_IS_OK(nt_status)) {
2035 char addr[INET6_ADDRSTRLEN];
2036 print_sockaddr(addr, sizeof(addr), &ss);
2037 DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
2038 nmb_namestr(&called), addr, nt_errstr(nt_status) ));
2039 cli_shutdown(cli);
2040 return nt_status;
2043 if (retry)
2044 *retry = True;
2046 if (!cli_session_request(cli, &calling, &called)) {
2047 char *p;
2048 DEBUG(1,("session request to %s failed (%s)\n",
2049 called.name, cli_errstr(cli)));
2050 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
2051 *p = 0;
2052 goto again;
2054 if (strcmp(called.name, STAR_SMBSERVER)) {
2055 make_nmb_name(&called , STAR_SMBSERVER, 0x20);
2056 goto again;
2058 return NT_STATUS_BAD_NETWORK_NAME;
2061 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
2062 cli->use_spnego = False;
2063 else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
2064 cli->use_kerberos = True;
2066 if ((flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) &&
2067 cli->use_kerberos) {
2068 cli->fallback_after_kerberos = true;
2071 nt_status = cli_negprot(cli);
2072 if (!NT_STATUS_IS_OK(nt_status)) {
2073 DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
2074 cli_shutdown(cli);
2075 return nt_status;
2078 *output_cli = cli;
2079 return NT_STATUS_OK;
2084 establishes a connection right up to doing tconX, password specified.
2085 @param output_cli A fully initialised cli structure, non-null only on success
2086 @param dest_host The netbios name of the remote host
2087 @param dest_ip (optional) The the destination IP, NULL for name based lookup
2088 @param port (optional) The destination port (0 for default)
2089 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
2090 @param service_type The 'type' of serivice.
2091 @param user Username, unix string
2092 @param domain User's domain
2093 @param password User's password, unencrypted unix string.
2094 @param retry bool. Did this connection fail with a retryable error ?
2097 NTSTATUS cli_full_connection(struct cli_state **output_cli,
2098 const char *my_name,
2099 const char *dest_host,
2100 struct sockaddr_storage *dest_ss, int port,
2101 const char *service, const char *service_type,
2102 const char *user, const char *domain,
2103 const char *password, int flags,
2104 int signing_state,
2105 bool *retry)
2107 NTSTATUS nt_status;
2108 struct cli_state *cli = NULL;
2109 int pw_len = password ? strlen(password)+1 : 0;
2111 *output_cli = NULL;
2113 if (password == NULL) {
2114 password = "";
2117 nt_status = cli_start_connection(&cli, my_name, dest_host,
2118 dest_ss, port, signing_state,
2119 flags, retry);
2121 if (!NT_STATUS_IS_OK(nt_status)) {
2122 return nt_status;
2125 nt_status = cli_session_setup(cli, user, password, pw_len, password,
2126 pw_len, domain);
2127 if (!NT_STATUS_IS_OK(nt_status)) {
2129 if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
2130 DEBUG(1,("failed session setup with %s\n",
2131 nt_errstr(nt_status)));
2132 cli_shutdown(cli);
2133 return nt_status;
2136 nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
2137 if (!NT_STATUS_IS_OK(nt_status)) {
2138 DEBUG(1,("anonymous failed session setup with %s\n",
2139 nt_errstr(nt_status)));
2140 cli_shutdown(cli);
2141 return nt_status;
2145 if (service) {
2146 nt_status = cli_tcon_andx(cli, service, service_type, password,
2147 pw_len);
2148 if (!NT_STATUS_IS_OK(nt_status)) {
2149 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
2150 cli_shutdown(cli);
2151 if (NT_STATUS_IS_OK(nt_status)) {
2152 nt_status = NT_STATUS_UNSUCCESSFUL;
2154 return nt_status;
2158 nt_status = cli_init_creds(cli, user, domain, password);
2159 if (!NT_STATUS_IS_OK(nt_status)) {
2160 cli_shutdown(cli);
2161 return nt_status;
2164 *output_cli = cli;
2165 return NT_STATUS_OK;
2168 /****************************************************************************
2169 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
2170 ****************************************************************************/
2172 bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
2173 struct sockaddr_storage *pdest_ss)
2175 struct nmb_name calling, called;
2177 make_nmb_name(&calling, srchost, 0x0);
2180 * If the called name is an IP address
2181 * then use *SMBSERVER immediately.
2184 if(is_ipaddress(desthost)) {
2185 make_nmb_name(&called, STAR_SMBSERVER, 0x20);
2186 } else {
2187 make_nmb_name(&called, desthost, 0x20);
2190 if (!cli_session_request(*ppcli, &calling, &called)) {
2191 NTSTATUS status;
2192 struct nmb_name smbservername;
2194 make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
2197 * If the name wasn't *SMBSERVER then
2198 * try with *SMBSERVER if the first name fails.
2201 if (nmb_name_equal(&called, &smbservername)) {
2204 * The name used was *SMBSERVER, don't bother with another name.
2207 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
2208 with error %s.\n", desthost, cli_errstr(*ppcli) ));
2209 return False;
2212 /* Try again... */
2213 cli_shutdown(*ppcli);
2215 *ppcli = cli_initialise();
2216 if (!*ppcli) {
2217 /* Out of memory... */
2218 return False;
2221 status = cli_connect(*ppcli, desthost, pdest_ss);
2222 if (!NT_STATUS_IS_OK(status) ||
2223 !cli_session_request(*ppcli, &calling, &smbservername)) {
2224 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
2225 name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
2226 return False;
2230 return True;
2233 /****************************************************************************
2234 Send an old style tcon.
2235 ****************************************************************************/
2236 NTSTATUS cli_raw_tcon(struct cli_state *cli,
2237 const char *service, const char *pass, const char *dev,
2238 uint16 *max_xmit, uint16 *tid)
2240 char *p;
2242 if (!lp_client_plaintext_auth() && (*pass)) {
2243 DEBUG(1, ("Server requested plaintext password but 'client "
2244 "plaintext auth' is disabled\n"));
2245 return NT_STATUS_ACCESS_DENIED;
2248 memset(cli->outbuf,'\0',smb_size);
2249 memset(cli->inbuf,'\0',smb_size);
2251 cli_set_message(cli->outbuf, 0, 0, True);
2252 SCVAL(cli->outbuf,smb_com,SMBtcon);
2253 cli_setup_packet(cli);
2255 p = smb_buf(cli->outbuf);
2256 *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
2257 *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
2258 *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
2260 cli_setup_bcc(cli, p);
2262 cli_send_smb(cli);
2263 if (!cli_receive_smb(cli)) {
2264 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2267 if (cli_is_error(cli)) {
2268 return cli_nt_error(cli);
2271 *max_xmit = SVAL(cli->inbuf, smb_vwv0);
2272 *tid = SVAL(cli->inbuf, smb_vwv1);
2274 return NT_STATUS_OK;
2277 /* Return a cli_state pointing at the IPC$ share for the given server */
2279 struct cli_state *get_ipc_connect(char *server,
2280 struct sockaddr_storage *server_ss,
2281 const struct user_auth_info *user_info)
2283 struct cli_state *cli;
2284 NTSTATUS nt_status;
2285 uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
2287 if (user_info->use_kerberos) {
2288 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
2291 nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
2292 user_info->username ? user_info->username : "",
2293 lp_workgroup(),
2294 user_info->password ? user_info->password : "",
2295 flags,
2296 Undefined, NULL);
2298 if (NT_STATUS_IS_OK(nt_status)) {
2299 return cli;
2300 } else if (is_ipaddress(server)) {
2301 /* windows 9* needs a correct NMB name for connections */
2302 fstring remote_name;
2304 if (name_status_find("*", 0, 0, server_ss, remote_name)) {
2305 cli = get_ipc_connect(remote_name, server_ss, user_info);
2306 if (cli)
2307 return cli;
2310 return NULL;
2314 * Given the IP address of a master browser on the network, return its
2315 * workgroup and connect to it.
2317 * This function is provided to allow additional processing beyond what
2318 * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
2319 * browsers and obtain each master browsers' list of domains (in case the
2320 * first master browser is recently on the network and has not yet
2321 * synchronized with other master browsers and therefore does not yet have the
2322 * entire network browse list)
2325 struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
2326 struct ip_service *mb_ip,
2327 const struct user_auth_info *user_info,
2328 char **pp_workgroup_out)
2330 char addr[INET6_ADDRSTRLEN];
2331 fstring name;
2332 struct cli_state *cli;
2333 struct sockaddr_storage server_ss;
2335 *pp_workgroup_out = NULL;
2337 print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
2338 DEBUG(99, ("Looking up name of master browser %s\n",
2339 addr));
2342 * Do a name status query to find out the name of the master browser.
2343 * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
2344 * master browser will not respond to a wildcard query (or, at least,
2345 * an NT4 server acting as the domain master browser will not).
2347 * We might be able to use ONLY the query on MSBROWSE, but that's not
2348 * yet been tested with all Windows versions, so until it is, leave
2349 * the original wildcard query as the first choice and fall back to
2350 * MSBROWSE if the wildcard query fails.
2352 if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
2353 !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
2355 DEBUG(99, ("Could not retrieve name status for %s\n",
2356 addr));
2357 return NULL;
2360 if (!find_master_ip(name, &server_ss)) {
2361 DEBUG(99, ("Could not find master ip for %s\n", name));
2362 return NULL;
2365 *pp_workgroup_out = talloc_strdup(ctx, name);
2367 DEBUG(4, ("found master browser %s, %s\n", name, addr));
2369 print_sockaddr(addr, sizeof(addr), &server_ss);
2370 cli = get_ipc_connect(addr, &server_ss, user_info);
2372 return cli;
2376 * Return the IP address and workgroup of a master browser on the network, and
2377 * connect to it.
2380 struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
2381 const struct user_auth_info *user_info,
2382 char **pp_workgroup_out)
2384 struct ip_service *ip_list;
2385 struct cli_state *cli;
2386 int i, count;
2388 *pp_workgroup_out = NULL;
2390 DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
2392 /* Go looking for workgroups by broadcasting on the local network */
2394 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
2395 &count))) {
2396 DEBUG(99, ("No master browsers responded\n"));
2397 return False;
2400 for (i = 0; i < count; i++) {
2401 char addr[INET6_ADDRSTRLEN];
2402 print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
2403 DEBUG(99, ("Found master browser %s\n", addr));
2405 cli = get_ipc_connect_master_ip(ctx, &ip_list[i],
2406 user_info, pp_workgroup_out);
2407 if (cli)
2408 return(cli);
2411 return NULL;