s3:libsmb: remove unused cli_state->dfsroot
[Samba.git] / source3 / libsmb / cliconnect.c
blob13e77046cfb7b2baa984d784164040128c802bce
1 /*
2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Andrew Bartlett 2001-2003
6 Copyright (C) Volker Lendecke 2011
7 Copyright (C) Jeremy Allison 2011
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "libsmb/libsmb.h"
25 #include "auth_info.h"
26 #include "../libcli/auth/libcli_auth.h"
27 #include "../libcli/auth/spnego.h"
28 #include "smb_krb5.h"
29 #include "../auth/ntlmssp/ntlmssp.h"
30 #include "libads/kerberos_proto.h"
31 #include "krb5_env.h"
32 #include "../lib/util/tevent_ntstatus.h"
33 #include "async_smb.h"
34 #include "libsmb/nmblib.h"
35 #include "librpc/ndr/libndr.h"
36 #include "../libcli/smb/smbXcli_base.h"
37 #include "smb2cli.h"
39 #define STAR_SMBSERVER "*SMBSERVER"
41 /********************************************************
42 Utility function to ensure we always return at least
43 a valid char * pointer to an empty string for the
44 cli->server_os, cli->server_type and cli->server_domain
45 strings.
46 *******************************************************/
48 static NTSTATUS smb_bytes_talloc_string(TALLOC_CTX *mem_ctx,
49 const uint8_t *hdr,
50 char **dest,
51 uint8_t *src,
52 size_t srclen,
53 ssize_t *destlen)
55 *destlen = clistr_pull_talloc(mem_ctx,
56 (const char *)hdr,
57 SVAL(hdr, HDR_FLG2),
58 dest,
59 (char *)src,
60 srclen,
61 STR_TERMINATE);
62 if (*destlen == -1) {
63 return NT_STATUS_NO_MEMORY;
66 if (*dest == NULL) {
67 *dest = talloc_strdup(mem_ctx, "");
68 if (*dest == NULL) {
69 return NT_STATUS_NO_MEMORY;
72 return NT_STATUS_OK;
75 /****************************************************************************
76 Do an old lanman2 style session setup.
77 ****************************************************************************/
79 struct cli_session_setup_lanman2_state {
80 struct cli_state *cli;
81 uint16_t vwv[10];
82 const char *user;
85 static void cli_session_setup_lanman2_done(struct tevent_req *subreq);
87 static struct tevent_req *cli_session_setup_lanman2_send(
88 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
89 struct cli_state *cli, const char *user,
90 const char *pass, size_t passlen,
91 const char *workgroup)
93 struct tevent_req *req, *subreq;
94 struct cli_session_setup_lanman2_state *state;
95 DATA_BLOB lm_response = data_blob_null;
96 uint16_t *vwv;
97 uint8_t *bytes;
98 char *tmp;
99 uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
101 req = tevent_req_create(mem_ctx, &state,
102 struct cli_session_setup_lanman2_state);
103 if (req == NULL) {
104 return NULL;
106 state->cli = cli;
107 state->user = user;
108 vwv = state->vwv;
111 * if in share level security then don't send a password now
113 if (!(sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
114 passlen = 0;
117 if (passlen > 0
118 && (sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
119 && passlen != 24) {
121 * Encrypted mode needed, and non encrypted password
122 * supplied.
124 lm_response = data_blob(NULL, 24);
125 if (tevent_req_nomem(lm_response.data, req)) {
126 return tevent_req_post(req, ev);
129 if (!SMBencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
130 (uint8_t *)lm_response.data)) {
131 DEBUG(1, ("Password is > 14 chars in length, and is "
132 "therefore incompatible with Lanman "
133 "authentication\n"));
134 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
135 return tevent_req_post(req, ev);
137 } else if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)
138 && passlen == 24) {
140 * Encrypted mode needed, and encrypted password
141 * supplied.
143 lm_response = data_blob(pass, passlen);
144 if (tevent_req_nomem(lm_response.data, req)) {
145 return tevent_req_post(req, ev);
147 } else if (passlen > 0) {
148 uint8_t *buf;
149 size_t converted_size;
151 * Plaintext mode needed, assume plaintext supplied.
153 buf = talloc_array(talloc_tos(), uint8_t, 0);
154 buf = smb_bytes_push_str(buf, smbXcli_conn_use_unicode(cli->conn), pass, passlen+1,
155 &converted_size);
156 if (tevent_req_nomem(buf, req)) {
157 return tevent_req_post(req, ev);
159 lm_response = data_blob(pass, passlen);
160 TALLOC_FREE(buf);
161 if (tevent_req_nomem(lm_response.data, req)) {
162 return tevent_req_post(req, ev);
166 SCVAL(vwv+0, 0, 0xff);
167 SCVAL(vwv+0, 1, 0);
168 SSVAL(vwv+1, 0, 0);
169 SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
170 SSVAL(vwv+3, 0, 2);
171 SSVAL(vwv+4, 0, 1);
172 SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
173 SSVAL(vwv+7, 0, lm_response.length);
175 bytes = talloc_array(state, uint8_t, lm_response.length);
176 if (tevent_req_nomem(bytes, req)) {
177 return tevent_req_post(req, ev);
179 if (lm_response.length != 0) {
180 memcpy(bytes, lm_response.data, lm_response.length);
182 data_blob_free(&lm_response);
184 tmp = talloc_strdup_upper(talloc_tos(), user);
185 if (tevent_req_nomem(tmp, req)) {
186 return tevent_req_post(req, ev);
188 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
189 NULL);
190 TALLOC_FREE(tmp);
192 tmp = talloc_strdup_upper(talloc_tos(), workgroup);
193 if (tevent_req_nomem(tmp, req)) {
194 return tevent_req_post(req, ev);
196 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
197 NULL);
198 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
199 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
201 if (tevent_req_nomem(bytes, req)) {
202 return tevent_req_post(req, ev);
205 subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 10, vwv,
206 talloc_get_size(bytes), bytes);
207 if (tevent_req_nomem(subreq, req)) {
208 return tevent_req_post(req, ev);
210 tevent_req_set_callback(subreq, cli_session_setup_lanman2_done, req);
211 return req;
214 static void cli_session_setup_lanman2_done(struct tevent_req *subreq)
216 struct tevent_req *req = tevent_req_callback_data(
217 subreq, struct tevent_req);
218 struct cli_session_setup_lanman2_state *state = tevent_req_data(
219 req, struct cli_session_setup_lanman2_state);
220 struct cli_state *cli = state->cli;
221 uint32_t num_bytes;
222 uint8_t *in;
223 uint8_t *inhdr;
224 uint8_t *bytes;
225 uint8_t *p;
226 NTSTATUS status;
227 ssize_t ret;
228 uint8_t wct;
229 uint16_t *vwv;
231 status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
232 &num_bytes, &bytes);
233 TALLOC_FREE(subreq);
234 if (!NT_STATUS_IS_OK(status)) {
235 tevent_req_nterror(req, status);
236 return;
239 inhdr = in + NBT_HDR_SIZE;
240 p = bytes;
242 cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
243 cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
245 status = smb_bytes_talloc_string(cli,
246 inhdr,
247 &cli->server_os,
249 bytes+num_bytes-p,
250 &ret);
252 if (!NT_STATUS_IS_OK(status)) {
253 tevent_req_nterror(req, status);
254 return;
256 p += ret;
258 status = smb_bytes_talloc_string(cli,
259 inhdr,
260 &cli->server_type,
262 bytes+num_bytes-p,
263 &ret);
265 if (!NT_STATUS_IS_OK(status)) {
266 tevent_req_nterror(req, status);
267 return;
269 p += ret;
271 status = smb_bytes_talloc_string(cli,
272 inhdr,
273 &cli->server_domain,
275 bytes+num_bytes-p,
276 &ret);
278 if (!NT_STATUS_IS_OK(status)) {
279 tevent_req_nterror(req, status);
280 return;
282 p += ret;
284 status = cli_set_username(cli, state->user);
285 if (tevent_req_nterror(req, status)) {
286 return;
288 tevent_req_done(req);
291 static NTSTATUS cli_session_setup_lanman2_recv(struct tevent_req *req)
293 return tevent_req_simple_recv_ntstatus(req);
296 /****************************************************************************
297 Work out suitable capabilities to offer the server.
298 ****************************************************************************/
300 static uint32_t cli_session_setup_capabilities(struct cli_state *cli,
301 uint32_t sesssetup_capabilities)
303 uint32_t client_capabilities = smb1cli_conn_capabilities(cli->conn);
306 * We only send capabilities based on the mask for:
307 * - client only flags
308 * - flags used in both directions
310 * We do not echo the server only flags, except some legacy flags.
312 * SMB_CAP_LEGACY_CLIENT_MASK contains CAP_LARGE_READX and
313 * CAP_LARGE_WRITEX in order to allow us to do large reads
314 * against old Samba releases (<= 3.6.x).
316 client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_LEGACY_CLIENT_MASK);
319 * Session Setup specific flags CAP_DYNAMIC_REAUTH
320 * and CAP_EXTENDED_SECURITY are passed by the caller.
321 * We need that in order to do guest logins even if
322 * CAP_EXTENDED_SECURITY is negotiated.
324 client_capabilities &= ~(CAP_DYNAMIC_REAUTH|CAP_EXTENDED_SECURITY);
325 sesssetup_capabilities &= (CAP_DYNAMIC_REAUTH|CAP_EXTENDED_SECURITY);
326 client_capabilities |= sesssetup_capabilities;
328 return client_capabilities;
331 /****************************************************************************
332 Do a NT1 guest session setup.
333 ****************************************************************************/
335 struct cli_session_setup_guest_state {
336 struct cli_state *cli;
337 uint16_t vwv[13];
338 struct iovec bytes;
341 static void cli_session_setup_guest_done(struct tevent_req *subreq);
343 struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
344 struct tevent_context *ev,
345 struct cli_state *cli,
346 struct tevent_req **psmbreq)
348 struct tevent_req *req, *subreq;
349 struct cli_session_setup_guest_state *state;
350 uint16_t *vwv;
351 uint8_t *bytes;
353 req = tevent_req_create(mem_ctx, &state,
354 struct cli_session_setup_guest_state);
355 if (req == NULL) {
356 return NULL;
358 state->cli = cli;
359 vwv = state->vwv;
361 SCVAL(vwv+0, 0, 0xFF);
362 SCVAL(vwv+0, 1, 0);
363 SSVAL(vwv+1, 0, 0);
364 SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
365 SSVAL(vwv+3, 0, 2);
366 SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
367 SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
368 SSVAL(vwv+7, 0, 0);
369 SSVAL(vwv+8, 0, 0);
370 SSVAL(vwv+9, 0, 0);
371 SSVAL(vwv+10, 0, 0);
372 SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0));
374 bytes = talloc_array(state, uint8_t, 0);
376 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, /* username */
377 NULL);
378 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "", 1, /* workgroup */
379 NULL);
380 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
381 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
383 if (bytes == NULL) {
384 TALLOC_FREE(req);
385 return NULL;
388 state->bytes.iov_base = (void *)bytes;
389 state->bytes.iov_len = talloc_get_size(bytes);
391 subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
392 1, &state->bytes);
393 if (subreq == NULL) {
394 TALLOC_FREE(req);
395 return NULL;
397 tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
398 *psmbreq = subreq;
399 return req;
402 struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
403 struct tevent_context *ev,
404 struct cli_state *cli)
406 struct tevent_req *req, *subreq;
407 NTSTATUS status;
409 req = cli_session_setup_guest_create(mem_ctx, ev, cli, &subreq);
410 if (req == NULL) {
411 return NULL;
414 status = smb1cli_req_chain_submit(&subreq, 1);
415 if (!NT_STATUS_IS_OK(status)) {
416 tevent_req_nterror(req, status);
417 return tevent_req_post(req, ev);
419 return req;
422 static void cli_session_setup_guest_done(struct tevent_req *subreq)
424 struct tevent_req *req = tevent_req_callback_data(
425 subreq, struct tevent_req);
426 struct cli_session_setup_guest_state *state = tevent_req_data(
427 req, struct cli_session_setup_guest_state);
428 struct cli_state *cli = state->cli;
429 uint32_t num_bytes;
430 uint8_t *in;
431 uint8_t *inhdr;
432 uint8_t *bytes;
433 uint8_t *p;
434 NTSTATUS status;
435 ssize_t ret;
436 uint8_t wct;
437 uint16_t *vwv;
439 status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
440 &num_bytes, &bytes);
441 TALLOC_FREE(subreq);
442 if (!NT_STATUS_IS_OK(status)) {
443 tevent_req_nterror(req, status);
444 return;
447 inhdr = in + NBT_HDR_SIZE;
448 p = bytes;
450 cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
451 cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
453 status = smb_bytes_talloc_string(cli,
454 inhdr,
455 &cli->server_os,
457 bytes+num_bytes-p,
458 &ret);
460 if (!NT_STATUS_IS_OK(status)) {
461 tevent_req_nterror(req, status);
462 return;
464 p += ret;
466 status = smb_bytes_talloc_string(cli,
467 inhdr,
468 &cli->server_type,
470 bytes+num_bytes-p,
471 &ret);
473 if (!NT_STATUS_IS_OK(status)) {
474 tevent_req_nterror(req, status);
475 return;
477 p += ret;
479 status = smb_bytes_talloc_string(cli,
480 inhdr,
481 &cli->server_domain,
483 bytes+num_bytes-p,
484 &ret);
486 if (!NT_STATUS_IS_OK(status)) {
487 tevent_req_nterror(req, status);
488 return;
490 p += ret;
492 status = cli_set_username(cli, "");
493 if (!NT_STATUS_IS_OK(status)) {
494 tevent_req_nterror(req, status);
495 return;
497 tevent_req_done(req);
500 NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
502 return tevent_req_simple_recv_ntstatus(req);
505 /****************************************************************************
506 Do a NT1 plaintext session setup.
507 ****************************************************************************/
509 struct cli_session_setup_plain_state {
510 struct cli_state *cli;
511 uint16_t vwv[13];
512 const char *user;
515 static void cli_session_setup_plain_done(struct tevent_req *subreq);
517 static struct tevent_req *cli_session_setup_plain_send(
518 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
519 struct cli_state *cli,
520 const char *user, const char *pass, const char *workgroup)
522 struct tevent_req *req, *subreq;
523 struct cli_session_setup_plain_state *state;
524 uint16_t *vwv;
525 uint8_t *bytes;
526 size_t passlen;
527 char *version;
529 req = tevent_req_create(mem_ctx, &state,
530 struct cli_session_setup_plain_state);
531 if (req == NULL) {
532 return NULL;
534 state->cli = cli;
535 state->user = user;
536 vwv = state->vwv;
538 SCVAL(vwv+0, 0, 0xff);
539 SCVAL(vwv+0, 1, 0);
540 SSVAL(vwv+1, 0, 0);
541 SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
542 SSVAL(vwv+3, 0, 2);
543 SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
544 SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
545 SSVAL(vwv+7, 0, 0);
546 SSVAL(vwv+8, 0, 0);
547 SSVAL(vwv+9, 0, 0);
548 SSVAL(vwv+10, 0, 0);
549 SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0));
551 bytes = talloc_array(state, uint8_t, 0);
552 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), pass, strlen(pass)+1,
553 &passlen);
554 if (tevent_req_nomem(bytes, req)) {
555 return tevent_req_post(req, ev);
557 SSVAL(vwv + (smbXcli_conn_use_unicode(cli->conn) ? 8 : 7), 0, passlen);
559 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
560 user, strlen(user)+1, NULL);
561 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
562 workgroup, strlen(workgroup)+1, NULL);
563 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
564 "Unix", 5, NULL);
566 version = talloc_asprintf(talloc_tos(), "Samba %s",
567 samba_version_string());
568 if (tevent_req_nomem(version, req)){
569 return tevent_req_post(req, ev);
571 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
572 version, strlen(version)+1, NULL);
573 TALLOC_FREE(version);
575 if (tevent_req_nomem(bytes, req)) {
576 return tevent_req_post(req, ev);
579 subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
580 talloc_get_size(bytes), bytes);
581 if (tevent_req_nomem(subreq, req)) {
582 return tevent_req_post(req, ev);
584 tevent_req_set_callback(subreq, cli_session_setup_plain_done, req);
585 return req;
588 static void cli_session_setup_plain_done(struct tevent_req *subreq)
590 struct tevent_req *req = tevent_req_callback_data(
591 subreq, struct tevent_req);
592 struct cli_session_setup_plain_state *state = tevent_req_data(
593 req, struct cli_session_setup_plain_state);
594 struct cli_state *cli = state->cli;
595 uint32_t num_bytes;
596 uint8_t *in;
597 uint8_t *inhdr;
598 uint8_t *bytes;
599 uint8_t *p;
600 NTSTATUS status;
601 ssize_t ret;
602 uint8_t wct;
603 uint16_t *vwv;
605 status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
606 &num_bytes, &bytes);
607 TALLOC_FREE(subreq);
608 if (tevent_req_nterror(req, status)) {
609 return;
612 inhdr = in + NBT_HDR_SIZE;
613 p = bytes;
615 cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
616 cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
618 status = smb_bytes_talloc_string(cli,
619 inhdr,
620 &cli->server_os,
622 bytes+num_bytes-p,
623 &ret);
625 if (!NT_STATUS_IS_OK(status)) {
626 tevent_req_nterror(req, status);
627 return;
629 p += ret;
631 status = smb_bytes_talloc_string(cli,
632 inhdr,
633 &cli->server_type,
635 bytes+num_bytes-p,
636 &ret);
638 if (!NT_STATUS_IS_OK(status)) {
639 tevent_req_nterror(req, status);
640 return;
642 p += ret;
644 status = smb_bytes_talloc_string(cli,
645 inhdr,
646 &cli->server_domain,
648 bytes+num_bytes-p,
649 &ret);
651 if (!NT_STATUS_IS_OK(status)) {
652 tevent_req_nterror(req, status);
653 return;
655 p += ret;
657 status = cli_set_username(cli, state->user);
658 if (tevent_req_nterror(req, status)) {
659 return;
662 tevent_req_done(req);
665 static NTSTATUS cli_session_setup_plain_recv(struct tevent_req *req)
667 return tevent_req_simple_recv_ntstatus(req);
670 /****************************************************************************
671 do a NT1 NTLM/LM encrypted session setup - for when extended security
672 is not negotiated.
673 @param cli client state to create do session setup on
674 @param user username
675 @param pass *either* cleartext password (passlen !=24) or LM response.
676 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
677 @param workgroup The user's domain.
678 ****************************************************************************/
680 struct cli_session_setup_nt1_state {
681 struct cli_state *cli;
682 uint16_t vwv[13];
683 DATA_BLOB response;
684 DATA_BLOB session_key;
685 const char *user;
688 static void cli_session_setup_nt1_done(struct tevent_req *subreq);
690 static struct tevent_req *cli_session_setup_nt1_send(
691 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
692 struct cli_state *cli, const char *user,
693 const char *pass, size_t passlen,
694 const char *ntpass, size_t ntpasslen,
695 const char *workgroup)
697 struct tevent_req *req, *subreq;
698 struct cli_session_setup_nt1_state *state;
699 DATA_BLOB lm_response = data_blob_null;
700 DATA_BLOB nt_response = data_blob_null;
701 DATA_BLOB session_key = data_blob_null;
702 uint16_t *vwv;
703 uint8_t *bytes;
704 char *workgroup_upper;
706 req = tevent_req_create(mem_ctx, &state,
707 struct cli_session_setup_nt1_state);
708 if (req == NULL) {
709 return NULL;
711 state->cli = cli;
712 state->user = user;
713 vwv = state->vwv;
715 if (passlen == 0) {
716 /* do nothing - guest login */
717 } else if (passlen != 24) {
718 if (lp_client_ntlmv2_auth()) {
719 DATA_BLOB server_chal;
720 DATA_BLOB names_blob;
722 server_chal =
723 data_blob_const(smb1cli_conn_server_challenge(cli->conn),
727 * note that the 'workgroup' here is a best
728 * guess - we don't know the server's domain
729 * at this point. Windows clients also don't
730 * use hostname...
732 names_blob = NTLMv2_generate_names_blob(
733 NULL, NULL, workgroup);
735 if (tevent_req_nomem(names_blob.data, req)) {
736 return tevent_req_post(req, ev);
739 if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass,
740 &server_chal, &names_blob,
741 &lm_response, &nt_response,
742 NULL, &session_key)) {
743 data_blob_free(&names_blob);
744 tevent_req_nterror(
745 req, NT_STATUS_ACCESS_DENIED);
746 return tevent_req_post(req, ev);
748 data_blob_free(&names_blob);
750 } else {
751 uchar nt_hash[16];
752 E_md4hash(pass, nt_hash);
754 #ifdef LANMAN_ONLY
755 nt_response = data_blob_null;
756 #else
757 nt_response = data_blob(NULL, 24);
758 if (tevent_req_nomem(nt_response.data, req)) {
759 return tevent_req_post(req, ev);
762 SMBNTencrypt(pass, smb1cli_conn_server_challenge(cli->conn),
763 nt_response.data);
764 #endif
765 /* non encrypted password supplied. Ignore ntpass. */
766 if (lp_client_lanman_auth()) {
768 lm_response = data_blob(NULL, 24);
769 if (tevent_req_nomem(lm_response.data, req)) {
770 return tevent_req_post(req, ev);
773 if (!SMBencrypt(pass,
774 smb1cli_conn_server_challenge(cli->conn),
775 lm_response.data)) {
777 * Oops, the LM response is
778 * invalid, just put the NT
779 * response there instead
781 data_blob_free(&lm_response);
782 lm_response = data_blob(
783 nt_response.data,
784 nt_response.length);
786 } else {
788 * LM disabled, place NT# in LM field
789 * instead
791 lm_response = data_blob(
792 nt_response.data, nt_response.length);
795 if (tevent_req_nomem(lm_response.data, req)) {
796 return tevent_req_post(req, ev);
799 session_key = data_blob(NULL, 16);
800 if (tevent_req_nomem(session_key.data, req)) {
801 return tevent_req_post(req, ev);
803 #ifdef LANMAN_ONLY
804 E_deshash(pass, session_key.data);
805 memset(&session_key.data[8], '\0', 8);
806 #else
807 SMBsesskeygen_ntv1(nt_hash, session_key.data);
808 #endif
810 } else {
811 /* pre-encrypted password supplied. Only used for
812 security=server, can't do
813 signing because we don't have original key */
815 lm_response = data_blob(pass, passlen);
816 if (tevent_req_nomem(lm_response.data, req)) {
817 return tevent_req_post(req, ev);
820 nt_response = data_blob(ntpass, ntpasslen);
821 if (tevent_req_nomem(nt_response.data, req)) {
822 return tevent_req_post(req, ev);
826 #ifdef LANMAN_ONLY
827 state->response = data_blob_talloc(
828 state, lm_response.data, lm_response.length);
829 #else
830 state->response = data_blob_talloc(
831 state, nt_response.data, nt_response.length);
832 #endif
833 if (tevent_req_nomem(state->response.data, req)) {
834 return tevent_req_post(req, ev);
837 if (session_key.data) {
838 state->session_key = data_blob_talloc(
839 state, session_key.data, session_key.length);
840 if (tevent_req_nomem(state->session_key.data, req)) {
841 return tevent_req_post(req, ev);
844 data_blob_free(&session_key);
846 SCVAL(vwv+0, 0, 0xff);
847 SCVAL(vwv+0, 1, 0);
848 SSVAL(vwv+1, 0, 0);
849 SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
850 SSVAL(vwv+3, 0, 2);
851 SSVAL(vwv+4, 0, cli_state_get_vc_num(cli));
852 SIVAL(vwv+5, 0, smb1cli_conn_server_session_key(cli->conn));
853 SSVAL(vwv+7, 0, lm_response.length);
854 SSVAL(vwv+8, 0, nt_response.length);
855 SSVAL(vwv+9, 0, 0);
856 SSVAL(vwv+10, 0, 0);
857 SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli, 0));
859 bytes = talloc_array(state, uint8_t,
860 lm_response.length + nt_response.length);
861 if (tevent_req_nomem(bytes, req)) {
862 return tevent_req_post(req, ev);
864 if (lm_response.length != 0) {
865 memcpy(bytes, lm_response.data, lm_response.length);
867 if (nt_response.length != 0) {
868 memcpy(bytes + lm_response.length,
869 nt_response.data, nt_response.length);
871 data_blob_free(&lm_response);
872 data_blob_free(&nt_response);
874 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
875 user, strlen(user)+1, NULL);
878 * Upper case here might help some NTLMv2 implementations
880 workgroup_upper = talloc_strdup_upper(talloc_tos(), workgroup);
881 if (tevent_req_nomem(workgroup_upper, req)) {
882 return tevent_req_post(req, ev);
884 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
885 workgroup_upper, strlen(workgroup_upper)+1,
886 NULL);
887 TALLOC_FREE(workgroup_upper);
889 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Unix", 5, NULL);
890 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), "Samba", 6, NULL);
891 if (tevent_req_nomem(bytes, req)) {
892 return tevent_req_post(req, ev);
895 subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
896 talloc_get_size(bytes), bytes);
897 if (tevent_req_nomem(subreq, req)) {
898 return tevent_req_post(req, ev);
900 tevent_req_set_callback(subreq, cli_session_setup_nt1_done, req);
901 return req;
904 static void cli_session_setup_nt1_done(struct tevent_req *subreq)
906 struct tevent_req *req = tevent_req_callback_data(
907 subreq, struct tevent_req);
908 struct cli_session_setup_nt1_state *state = tevent_req_data(
909 req, struct cli_session_setup_nt1_state);
910 struct cli_state *cli = state->cli;
911 uint32_t num_bytes;
912 uint8_t *in;
913 uint8_t *inhdr;
914 uint8_t *bytes;
915 uint8_t *p;
916 NTSTATUS status;
917 ssize_t ret;
918 uint8_t wct;
919 uint16_t *vwv;
921 status = cli_smb_recv(subreq, state, &in, 3, &wct, &vwv,
922 &num_bytes, &bytes);
923 TALLOC_FREE(subreq);
924 if (!NT_STATUS_IS_OK(status)) {
925 tevent_req_nterror(req, status);
926 return;
929 inhdr = in + NBT_HDR_SIZE;
930 p = bytes;
932 cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
933 cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
935 status = smb_bytes_talloc_string(cli,
936 inhdr,
937 &cli->server_os,
939 bytes+num_bytes-p,
940 &ret);
941 if (!NT_STATUS_IS_OK(status)) {
942 tevent_req_nterror(req, status);
943 return;
945 p += ret;
947 status = smb_bytes_talloc_string(cli,
948 inhdr,
949 &cli->server_type,
951 bytes+num_bytes-p,
952 &ret);
953 if (!NT_STATUS_IS_OK(status)) {
954 tevent_req_nterror(req, status);
955 return;
957 p += ret;
959 status = smb_bytes_talloc_string(cli,
960 inhdr,
961 &cli->server_domain,
963 bytes+num_bytes-p,
964 &ret);
965 if (!NT_STATUS_IS_OK(status)) {
966 tevent_req_nterror(req, status);
967 return;
969 p += ret;
971 status = cli_set_username(cli, state->user);
972 if (tevent_req_nterror(req, status)) {
973 return;
975 if (smb1cli_conn_activate_signing(cli->conn, state->session_key, state->response)
976 && !smb1cli_conn_check_signing(cli->conn, (uint8_t *)in, 1)) {
977 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
978 return;
980 if (state->session_key.data) {
981 struct smbXcli_session *session = state->cli->smb1.session;
983 status = smb1cli_session_set_session_key(session,
984 state->session_key);
985 if (tevent_req_nterror(req, status)) {
986 return;
989 tevent_req_done(req);
992 static NTSTATUS cli_session_setup_nt1_recv(struct tevent_req *req)
994 return tevent_req_simple_recv_ntstatus(req);
997 /* The following is calculated from :
998 * (smb_size-4) = 35
999 * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
1000 * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
1001 * end of packet.
1004 #define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
1006 struct cli_sesssetup_blob_state {
1007 struct tevent_context *ev;
1008 struct cli_state *cli;
1009 DATA_BLOB blob;
1010 uint16_t max_blob_size;
1011 uint16_t vwv[12];
1012 uint8_t *buf;
1014 DATA_BLOB smb2_blob;
1015 struct iovec *recv_iov;
1017 NTSTATUS status;
1018 uint8_t *inbuf;
1019 DATA_BLOB ret_blob;
1022 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
1023 struct tevent_req **psubreq);
1024 static void cli_sesssetup_blob_done(struct tevent_req *subreq);
1026 static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
1027 struct tevent_context *ev,
1028 struct cli_state *cli,
1029 DATA_BLOB blob)
1031 struct tevent_req *req, *subreq;
1032 struct cli_sesssetup_blob_state *state;
1033 uint32_t usable_space;
1035 req = tevent_req_create(mem_ctx, &state,
1036 struct cli_sesssetup_blob_state);
1037 if (req == NULL) {
1038 return NULL;
1040 state->ev = ev;
1041 state->blob = blob;
1042 state->cli = cli;
1044 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1045 usable_space = UINT16_MAX;
1046 } else {
1047 usable_space = cli_state_available_size(cli,
1048 BASE_SESSSETUP_BLOB_PACKET_SIZE);
1051 if (usable_space == 0) {
1052 DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
1053 "(not possible to send %u bytes)\n",
1054 BASE_SESSSETUP_BLOB_PACKET_SIZE + 1));
1055 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1056 return tevent_req_post(req, ev);
1058 state->max_blob_size = MIN(usable_space, 0xFFFF);
1060 if (!cli_sesssetup_blob_next(state, &subreq)) {
1061 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1062 return tevent_req_post(req, ev);
1064 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
1065 return req;
1068 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
1069 struct tevent_req **psubreq)
1071 struct tevent_req *subreq;
1072 uint16_t thistime;
1074 thistime = MIN(state->blob.length, state->max_blob_size);
1076 if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1078 state->smb2_blob.data = state->blob.data;
1079 state->smb2_blob.length = thistime;
1081 state->blob.data += thistime;
1082 state->blob.length -= thistime;
1084 subreq = smb2cli_session_setup_send(state, state->ev,
1085 state->cli->conn,
1086 state->cli->timeout,
1087 state->cli->smb2.session,
1088 0, /* in_flags */
1089 SMB2_CAP_DFS, /* in_capabilities */
1090 0, /* in_channel */
1091 0, /* in_previous_session_id */
1092 &state->smb2_blob);
1093 if (subreq == NULL) {
1094 return false;
1096 *psubreq = subreq;
1097 return true;
1100 SCVAL(state->vwv+0, 0, 0xFF);
1101 SCVAL(state->vwv+0, 1, 0);
1102 SSVAL(state->vwv+1, 0, 0);
1103 SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
1104 SSVAL(state->vwv+3, 0, 2);
1105 SSVAL(state->vwv+4, 0, 1);
1106 SIVAL(state->vwv+5, 0, 0);
1108 SSVAL(state->vwv+7, 0, thistime);
1110 SSVAL(state->vwv+8, 0, 0);
1111 SSVAL(state->vwv+9, 0, 0);
1112 SIVAL(state->vwv+10, 0,
1113 cli_session_setup_capabilities(state->cli, CAP_EXTENDED_SECURITY));
1115 state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
1116 thistime);
1117 if (state->buf == NULL) {
1118 return false;
1120 state->blob.data += thistime;
1121 state->blob.length -= thistime;
1123 state->buf = smb_bytes_push_str(state->buf, smbXcli_conn_use_unicode(state->cli->conn),
1124 "Unix", 5, NULL);
1125 state->buf = smb_bytes_push_str(state->buf, smbXcli_conn_use_unicode(state->cli->conn),
1126 "Samba", 6, NULL);
1127 if (state->buf == NULL) {
1128 return false;
1130 subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
1131 12, state->vwv,
1132 talloc_get_size(state->buf), state->buf);
1133 if (subreq == NULL) {
1134 return false;
1136 *psubreq = subreq;
1137 return true;
1140 static void cli_sesssetup_blob_done(struct tevent_req *subreq)
1142 struct tevent_req *req = tevent_req_callback_data(
1143 subreq, struct tevent_req);
1144 struct cli_sesssetup_blob_state *state = tevent_req_data(
1145 req, struct cli_sesssetup_blob_state);
1146 struct cli_state *cli = state->cli;
1147 uint8_t wct;
1148 uint16_t *vwv;
1149 uint32_t num_bytes;
1150 uint8_t *bytes;
1151 NTSTATUS status;
1152 uint8_t *p;
1153 uint16_t blob_length;
1154 uint8_t *in;
1155 uint8_t *inhdr;
1156 ssize_t ret;
1158 if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1159 status = smb2cli_session_setup_recv(subreq, state,
1160 &state->recv_iov,
1161 &state->ret_blob);
1162 } else {
1163 status = cli_smb_recv(subreq, state, &in, 4, &wct, &vwv,
1164 &num_bytes, &bytes);
1165 TALLOC_FREE(state->buf);
1167 TALLOC_FREE(subreq);
1168 if (!NT_STATUS_IS_OK(status)
1169 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1170 tevent_req_nterror(req, status);
1171 return;
1174 state->status = status;
1176 if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1177 goto next;
1180 state->inbuf = in;
1181 inhdr = in + NBT_HDR_SIZE;
1182 cli_state_set_uid(state->cli, SVAL(inhdr, HDR_UID));
1183 cli->is_guestlogin = ((SVAL(vwv+2, 0) & 1) != 0);
1185 blob_length = SVAL(vwv+3, 0);
1186 if (blob_length > num_bytes) {
1187 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1188 return;
1190 state->ret_blob = data_blob_const(bytes, blob_length);
1192 p = bytes + blob_length;
1194 status = smb_bytes_talloc_string(cli,
1195 inhdr,
1196 &cli->server_os,
1198 bytes+num_bytes-p,
1199 &ret);
1201 if (!NT_STATUS_IS_OK(status)) {
1202 tevent_req_nterror(req, status);
1203 return;
1205 p += ret;
1207 status = smb_bytes_talloc_string(cli,
1208 inhdr,
1209 &cli->server_type,
1211 bytes+num_bytes-p,
1212 &ret);
1214 if (!NT_STATUS_IS_OK(status)) {
1215 tevent_req_nterror(req, status);
1216 return;
1218 p += ret;
1220 status = smb_bytes_talloc_string(cli,
1221 inhdr,
1222 &cli->server_domain,
1224 bytes+num_bytes-p,
1225 &ret);
1227 if (!NT_STATUS_IS_OK(status)) {
1228 tevent_req_nterror(req, status);
1229 return;
1231 p += ret;
1233 next:
1234 if (state->blob.length != 0) {
1236 * More to send
1238 if (!cli_sesssetup_blob_next(state, &subreq)) {
1239 tevent_req_oom(req);
1240 return;
1242 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
1243 return;
1245 tevent_req_done(req);
1248 static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
1249 TALLOC_CTX *mem_ctx,
1250 DATA_BLOB *pblob,
1251 uint8_t **pinbuf,
1252 struct iovec **precv_iov)
1254 struct cli_sesssetup_blob_state *state = tevent_req_data(
1255 req, struct cli_sesssetup_blob_state);
1256 NTSTATUS status;
1257 uint8_t *inbuf;
1258 struct iovec *recv_iov;
1260 if (tevent_req_is_nterror(req, &status)) {
1261 TALLOC_FREE(state->cli->smb2.session);
1262 cli_state_set_uid(state->cli, UID_FIELD_INVALID);
1263 return status;
1266 inbuf = talloc_move(mem_ctx, &state->inbuf);
1267 recv_iov = talloc_move(mem_ctx, &state->recv_iov);
1268 if (pblob != NULL) {
1269 *pblob = state->ret_blob;
1271 if (pinbuf != NULL) {
1272 *pinbuf = inbuf;
1274 if (precv_iov != NULL) {
1275 *precv_iov = recv_iov;
1277 /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
1278 return state->status;
1281 #ifdef HAVE_KRB5
1283 /****************************************************************************
1284 Use in-memory credentials cache
1285 ****************************************************************************/
1287 static void use_in_memory_ccache(void) {
1288 setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
1291 /****************************************************************************
1292 Do a spnego/kerberos encrypted session setup.
1293 ****************************************************************************/
1295 struct cli_session_setup_kerberos_state {
1296 struct cli_state *cli;
1297 DATA_BLOB negTokenTarg;
1298 DATA_BLOB session_key_krb5;
1299 ADS_STATUS ads_status;
1302 static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
1304 static struct tevent_req *cli_session_setup_kerberos_send(
1305 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
1306 const char *principal)
1308 struct tevent_req *req, *subreq;
1309 struct cli_session_setup_kerberos_state *state;
1310 int rc;
1312 DEBUG(2,("Doing kerberos session setup\n"));
1314 req = tevent_req_create(mem_ctx, &state,
1315 struct cli_session_setup_kerberos_state);
1316 if (req == NULL) {
1317 return NULL;
1319 state->cli = cli;
1320 state->ads_status = ADS_SUCCESS;
1323 * Ok, this is cheating: spnego_gen_krb5_negTokenInit can block if
1324 * we have to acquire a ticket. To be fixed later :-)
1326 rc = spnego_gen_krb5_negTokenInit(state, principal, 0, &state->negTokenTarg,
1327 &state->session_key_krb5, 0, NULL, NULL);
1328 if (rc) {
1329 DEBUG(1, ("cli_session_setup_kerberos: "
1330 "spnego_gen_krb5_negTokenInit failed: %s\n",
1331 error_message(rc)));
1332 state->ads_status = ADS_ERROR_KRB5(rc);
1333 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1334 return tevent_req_post(req, ev);
1337 #if 0
1338 file_save("negTokenTarg.dat", state->negTokenTarg.data,
1339 state->negTokenTarg.length);
1340 #endif
1342 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1343 state->cli->smb2.session = smbXcli_session_create(cli,
1344 cli->conn);
1345 if (tevent_req_nomem(state->cli->smb2.session, req)) {
1346 return tevent_req_post(req, ev);
1350 subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
1351 if (tevent_req_nomem(subreq, req)) {
1352 return tevent_req_post(req, ev);
1354 tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
1355 return req;
1358 static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
1360 struct tevent_req *req = tevent_req_callback_data(
1361 subreq, struct tevent_req);
1362 struct cli_session_setup_kerberos_state *state = tevent_req_data(
1363 req, struct cli_session_setup_kerberos_state);
1364 uint8_t *inbuf = NULL;
1365 struct iovec *recv_iov = NULL;
1366 NTSTATUS status;
1368 status = cli_sesssetup_blob_recv(subreq, state,
1369 NULL, &inbuf, &recv_iov);
1370 TALLOC_FREE(subreq);
1371 if (!NT_STATUS_IS_OK(status)) {
1372 tevent_req_nterror(req, status);
1373 return;
1376 if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1377 struct smbXcli_session *session = state->cli->smb2.session;
1378 status = smb2cli_session_set_session_key(session,
1379 state->session_key_krb5,
1380 recv_iov);
1381 if (tevent_req_nterror(req, status)) {
1382 return;
1384 } else {
1385 struct smbXcli_session *session = state->cli->smb1.session;
1387 status = smb1cli_session_set_session_key(session,
1388 state->session_key_krb5);
1389 if (tevent_req_nterror(req, status)) {
1390 return;
1393 if (smb1cli_conn_activate_signing(state->cli->conn, state->session_key_krb5,
1394 data_blob_null)
1395 && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) {
1396 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1397 return;
1401 tevent_req_done(req);
1404 static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
1406 struct cli_session_setup_kerberos_state *state = tevent_req_data(
1407 req, struct cli_session_setup_kerberos_state);
1408 NTSTATUS status;
1410 if (tevent_req_is_nterror(req, &status)) {
1411 return ADS_ERROR_NT(status);
1413 return state->ads_status;
1416 #endif /* HAVE_KRB5 */
1418 /****************************************************************************
1419 Do a spnego/NTLMSSP encrypted session setup.
1420 ****************************************************************************/
1422 struct cli_session_setup_ntlmssp_state {
1423 struct tevent_context *ev;
1424 struct cli_state *cli;
1425 struct ntlmssp_state *ntlmssp_state;
1426 int turn;
1427 DATA_BLOB blob_out;
1430 static int cli_session_setup_ntlmssp_state_destructor(
1431 struct cli_session_setup_ntlmssp_state *state)
1433 if (state->ntlmssp_state != NULL) {
1434 TALLOC_FREE(state->ntlmssp_state);
1436 return 0;
1439 static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
1441 static struct tevent_req *cli_session_setup_ntlmssp_send(
1442 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
1443 const char *user, const char *pass, const char *domain)
1445 struct tevent_req *req, *subreq;
1446 struct cli_session_setup_ntlmssp_state *state;
1447 NTSTATUS status;
1448 DATA_BLOB blob_out;
1449 const char *OIDs_ntlm[] = {OID_NTLMSSP, NULL};
1451 req = tevent_req_create(mem_ctx, &state,
1452 struct cli_session_setup_ntlmssp_state);
1453 if (req == NULL) {
1454 return NULL;
1456 state->ev = ev;
1457 state->cli = cli;
1458 state->turn = 1;
1460 state->ntlmssp_state = NULL;
1461 talloc_set_destructor(
1462 state, cli_session_setup_ntlmssp_state_destructor);
1464 status = ntlmssp_client_start(state,
1465 lp_netbios_name(),
1466 lp_workgroup(),
1467 lp_client_ntlmv2_auth(),
1468 &state->ntlmssp_state);
1469 if (!NT_STATUS_IS_OK(status)) {
1470 goto fail;
1472 ntlmssp_want_feature(state->ntlmssp_state,
1473 NTLMSSP_FEATURE_SESSION_KEY);
1474 if (cli->use_ccache) {
1475 ntlmssp_want_feature(state->ntlmssp_state,
1476 NTLMSSP_FEATURE_CCACHE);
1478 status = ntlmssp_set_username(state->ntlmssp_state, user);
1479 if (!NT_STATUS_IS_OK(status)) {
1480 goto fail;
1482 status = ntlmssp_set_domain(state->ntlmssp_state, domain);
1483 if (!NT_STATUS_IS_OK(status)) {
1484 goto fail;
1486 if (cli->pw_nt_hash) {
1487 status = ntlmssp_set_password_hash(state->ntlmssp_state, pass);
1488 } else {
1489 status = ntlmssp_set_password(state->ntlmssp_state, pass);
1491 if (!NT_STATUS_IS_OK(status)) {
1492 goto fail;
1494 status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
1495 &blob_out);
1496 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1497 goto fail;
1500 state->blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL);
1501 data_blob_free(&blob_out);
1503 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
1504 state->cli->smb2.session = smbXcli_session_create(cli,
1505 cli->conn);
1506 if (tevent_req_nomem(state->cli->smb2.session, req)) {
1507 return tevent_req_post(req, ev);
1511 subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
1512 if (tevent_req_nomem(subreq, req)) {
1513 return tevent_req_post(req, ev);
1515 tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1516 return req;
1517 fail:
1518 tevent_req_nterror(req, status);
1519 return tevent_req_post(req, ev);
1522 static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
1524 struct tevent_req *req = tevent_req_callback_data(
1525 subreq, struct tevent_req);
1526 struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1527 req, struct cli_session_setup_ntlmssp_state);
1528 DATA_BLOB blob_in, msg_in, blob_out;
1529 uint8_t *inbuf = NULL;
1530 struct iovec *recv_iov = NULL;
1531 bool parse_ret;
1532 NTSTATUS status;
1534 status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
1535 &inbuf, &recv_iov);
1536 TALLOC_FREE(subreq);
1537 data_blob_free(&state->blob_out);
1539 if (NT_STATUS_IS_OK(status)) {
1540 if (state->cli->server_domain[0] == '\0') {
1541 TALLOC_FREE(state->cli->server_domain);
1542 state->cli->server_domain = talloc_strdup(state->cli,
1543 state->ntlmssp_state->server.netbios_domain);
1544 if (state->cli->server_domain == NULL) {
1545 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1546 return;
1550 if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
1551 struct smbXcli_session *session = state->cli->smb2.session;
1553 if (ntlmssp_is_anonymous(state->ntlmssp_state)) {
1555 * Windows server does not set the
1556 * SMB2_SESSION_FLAG_IS_GUEST nor
1557 * SMB2_SESSION_FLAG_IS_NULL flag.
1559 * This fix makes sure we do not try
1560 * to verify a signature on the final
1561 * session setup response.
1563 TALLOC_FREE(state->ntlmssp_state);
1564 tevent_req_done(req);
1565 return;
1568 status = smb2cli_session_set_session_key(session,
1569 state->ntlmssp_state->session_key,
1570 recv_iov);
1571 if (tevent_req_nterror(req, status)) {
1572 return;
1574 } else {
1575 struct smbXcli_session *session = state->cli->smb1.session;
1577 status = smb1cli_session_set_session_key(session,
1578 state->ntlmssp_state->session_key);
1579 if (tevent_req_nterror(req, status)) {
1580 return;
1583 if (smb1cli_conn_activate_signing(
1584 state->cli->conn, state->ntlmssp_state->session_key,
1585 data_blob_null)
1586 && !smb1cli_conn_check_signing(state->cli->conn, inbuf, 1)) {
1587 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1588 return;
1591 TALLOC_FREE(state->ntlmssp_state);
1592 tevent_req_done(req);
1593 return;
1595 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1596 tevent_req_nterror(req, status);
1597 return;
1600 if (blob_in.length == 0) {
1601 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1602 return;
1605 if ((state->turn == 1)
1606 && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1607 DATA_BLOB tmp_blob = data_blob_null;
1608 /* the server might give us back two challenges */
1609 parse_ret = spnego_parse_challenge(state, blob_in, &msg_in,
1610 &tmp_blob);
1611 data_blob_free(&tmp_blob);
1612 } else {
1613 parse_ret = spnego_parse_auth_response(state, blob_in, status,
1614 OID_NTLMSSP, &msg_in);
1616 state->turn += 1;
1618 if (!parse_ret) {
1619 DEBUG(3,("Failed to parse auth response\n"));
1620 if (NT_STATUS_IS_OK(status)
1621 || NT_STATUS_EQUAL(status,
1622 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1623 tevent_req_nterror(
1624 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1625 return;
1629 status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
1631 if (!NT_STATUS_IS_OK(status)
1632 && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1633 TALLOC_FREE(state->ntlmssp_state);
1634 tevent_req_nterror(req, status);
1635 return;
1638 state->blob_out = spnego_gen_auth(state, blob_out);
1639 if (tevent_req_nomem(state->blob_out.data, req)) {
1640 return;
1643 subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
1644 state->blob_out);
1645 if (tevent_req_nomem(subreq, req)) {
1646 return;
1648 tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1651 static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
1653 struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1654 req, struct cli_session_setup_ntlmssp_state);
1655 NTSTATUS status;
1657 if (tevent_req_is_nterror(req, &status)) {
1658 cli_state_set_uid(state->cli, UID_FIELD_INVALID);
1659 return status;
1661 return NT_STATUS_OK;
1664 #ifdef HAVE_KRB5
1666 static char *cli_session_setup_get_principal(
1667 TALLOC_CTX *mem_ctx, const char *spnego_principal,
1668 const char *remote_name, const char *dest_realm)
1670 char *principal = NULL;
1672 if (!lp_client_use_spnego_principal() ||
1673 strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1674 spnego_principal = NULL;
1676 if (spnego_principal != NULL) {
1677 DEBUG(3, ("cli_session_setup_spnego: using spnego provided "
1678 "principal %s\n", spnego_principal));
1679 return talloc_strdup(mem_ctx, spnego_principal);
1681 if (is_ipaddress(remote_name) ||
1682 strequal(remote_name, STAR_SMBSERVER)) {
1683 return NULL;
1686 DEBUG(3, ("cli_session_setup_spnego: using target "
1687 "hostname not SPNEGO principal\n"));
1689 if (dest_realm) {
1690 char *realm = strupper_talloc(talloc_tos(), dest_realm);
1691 if (realm == NULL) {
1692 return NULL;
1694 principal = talloc_asprintf(talloc_tos(), "cifs/%s@%s",
1695 remote_name, realm);
1696 TALLOC_FREE(realm);
1697 } else {
1698 principal = kerberos_get_principal_from_service_hostname(
1699 talloc_tos(), "cifs", remote_name, lp_realm());
1701 DEBUG(3, ("cli_session_setup_spnego: guessed server principal=%s\n",
1702 principal ? principal : "<null>"));
1704 return principal;
1706 #endif
1708 static char *cli_session_setup_get_account(TALLOC_CTX *mem_ctx,
1709 const char *principal)
1711 char *account, *p;
1713 account = talloc_strdup(mem_ctx, principal);
1714 if (account == NULL) {
1715 return NULL;
1717 p = strchr_m(account, '@');
1718 if (p != NULL) {
1719 *p = '\0';
1721 return account;
1724 /****************************************************************************
1725 Do a spnego encrypted session setup.
1727 user_domain: The shortname of the domain the user/machine is a member of.
1728 dest_realm: The realm we're connecting to, if NULL we use our default realm.
1729 ****************************************************************************/
1731 struct cli_session_setup_spnego_state {
1732 struct tevent_context *ev;
1733 struct cli_state *cli;
1734 const char *user;
1735 const char *account;
1736 const char *pass;
1737 const char *user_domain;
1738 const char *dest_realm;
1739 ADS_STATUS result;
1742 #ifdef HAVE_KRB5
1743 static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq);
1744 #endif
1746 static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq);
1748 static struct tevent_req *cli_session_setup_spnego_send(
1749 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
1750 const char *user, const char *pass, const char *user_domain,
1751 const char *dest_realm)
1753 struct tevent_req *req, *subreq;
1754 struct cli_session_setup_spnego_state *state;
1755 char *principal = NULL;
1756 char *OIDs[ASN1_MAX_OIDS];
1757 int i;
1758 const DATA_BLOB *server_blob;
1759 NTSTATUS status;
1761 req = tevent_req_create(mem_ctx, &state,
1762 struct cli_session_setup_spnego_state);
1763 if (req == NULL) {
1764 return NULL;
1766 state->ev = ev;
1767 state->cli = cli;
1768 state->user = user;
1769 state->pass = pass;
1770 state->user_domain = user_domain;
1771 state->dest_realm = dest_realm;
1773 state->account = cli_session_setup_get_account(state, user);
1774 if (tevent_req_nomem(state->account, req)) {
1775 return tevent_req_post(req, ev);
1778 server_blob = smbXcli_conn_server_gss_blob(cli->conn);
1780 DEBUG(3,("Doing spnego session setup (blob length=%lu)\n",
1781 (unsigned long)server_blob->length));
1783 /* the server might not even do spnego */
1784 if (server_blob->length == 0) {
1785 DEBUG(3,("server didn't supply a full spnego negprot\n"));
1786 goto ntlmssp;
1789 #if 0
1790 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
1791 #endif
1793 /* The server sent us the first part of the SPNEGO exchange in the
1794 * negprot reply. It is WRONG to depend on the principal sent in the
1795 * negprot reply, but right now we do it. If we don't receive one,
1796 * we try to best guess, then fall back to NTLM. */
1797 if (!spnego_parse_negTokenInit(state, *server_blob, OIDs,
1798 &principal, NULL) ||
1799 OIDs[0] == NULL) {
1800 state->result = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
1801 tevent_req_done(req);
1802 return tevent_req_post(req, ev);
1805 /* make sure the server understands kerberos */
1806 for (i=0;OIDs[i];i++) {
1807 if (i == 0)
1808 DEBUG(3,("got OID=%s\n", OIDs[i]));
1809 else
1810 DEBUGADD(3,("got OID=%s\n", OIDs[i]));
1811 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
1812 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
1813 cli->got_kerberos_mechanism = True;
1815 talloc_free(OIDs[i]);
1818 DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
1820 status = cli_set_username(cli, user);
1821 if (!NT_STATUS_IS_OK(status)) {
1822 state->result = ADS_ERROR_NT(status);
1823 tevent_req_done(req);
1824 return tevent_req_post(req, ev);
1827 #ifdef HAVE_KRB5
1828 /* If password is set we reauthenticate to kerberos server
1829 * and do not store results */
1831 if (user && *user && cli->got_kerberos_mechanism && cli->use_kerberos) {
1832 const char *remote_name = smbXcli_conn_remote_name(cli->conn);
1833 char *tmp;
1835 if (pass && *pass) {
1836 int ret;
1838 use_in_memory_ccache();
1839 ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
1841 if (ret){
1842 TALLOC_FREE(principal);
1843 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
1844 if (cli->fallback_after_kerberos)
1845 goto ntlmssp;
1846 state->result = ADS_ERROR_KRB5(ret);
1847 tevent_req_done(req);
1848 return tevent_req_post(req, ev);
1852 tmp = cli_session_setup_get_principal(
1853 talloc_tos(), principal, remote_name, dest_realm);
1854 TALLOC_FREE(principal);
1855 principal = tmp;
1857 if (principal) {
1858 subreq = cli_session_setup_kerberos_send(
1859 state, ev, cli, principal);
1860 if (tevent_req_nomem(subreq, req)) {
1861 return tevent_req_post(req, ev);
1863 tevent_req_set_callback(
1864 subreq, cli_session_setup_spnego_done_krb,
1865 req);
1866 return req;
1869 #endif
1871 ntlmssp:
1872 subreq = cli_session_setup_ntlmssp_send(
1873 state, ev, cli, state->account, pass, user_domain);
1874 if (tevent_req_nomem(subreq, req)) {
1875 return tevent_req_post(req, ev);
1877 tevent_req_set_callback(
1878 subreq, cli_session_setup_spnego_done_ntlmssp, req);
1879 return req;
1882 #ifdef HAVE_KRB5
1883 static void cli_session_setup_spnego_done_krb(struct tevent_req *subreq)
1885 struct tevent_req *req = tevent_req_callback_data(
1886 subreq, struct tevent_req);
1887 struct cli_session_setup_spnego_state *state = tevent_req_data(
1888 req, struct cli_session_setup_spnego_state);
1890 state->result = cli_session_setup_kerberos_recv(subreq);
1891 TALLOC_FREE(subreq);
1893 if (ADS_ERR_OK(state->result) ||
1894 !state->cli->fallback_after_kerberos) {
1895 tevent_req_done(req);
1896 return;
1899 subreq = cli_session_setup_ntlmssp_send(
1900 state, state->ev, state->cli, state->account, state->pass,
1901 state->user_domain);
1902 if (tevent_req_nomem(subreq, req)) {
1903 return;
1905 tevent_req_set_callback(subreq, cli_session_setup_spnego_done_ntlmssp,
1906 req);
1908 #endif
1910 static void cli_session_setup_spnego_done_ntlmssp(struct tevent_req *subreq)
1912 struct tevent_req *req = tevent_req_callback_data(
1913 subreq, struct tevent_req);
1914 struct cli_session_setup_spnego_state *state = tevent_req_data(
1915 req, struct cli_session_setup_spnego_state);
1916 NTSTATUS status;
1918 status = cli_session_setup_ntlmssp_recv(subreq);
1919 TALLOC_FREE(subreq);
1920 state->result = ADS_ERROR_NT(status);
1921 tevent_req_done(req);
1924 static ADS_STATUS cli_session_setup_spnego_recv(struct tevent_req *req)
1926 struct cli_session_setup_spnego_state *state = tevent_req_data(
1927 req, struct cli_session_setup_spnego_state);
1929 return state->result;
1932 struct cli_session_setup_state {
1933 uint8_t dummy;
1936 static void cli_session_setup_done_lanman2(struct tevent_req *subreq);
1937 static void cli_session_setup_done_spnego(struct tevent_req *subreq);
1938 static void cli_session_setup_done_guest(struct tevent_req *subreq);
1939 static void cli_session_setup_done_plain(struct tevent_req *subreq);
1940 static void cli_session_setup_done_nt1(struct tevent_req *subreq);
1942 /****************************************************************************
1943 Send a session setup. The username and workgroup is in UNIX character
1944 format and must be converted to DOS codepage format before sending. If the
1945 password is in plaintext, the same should be done.
1946 ****************************************************************************/
1948 struct tevent_req *cli_session_setup_send(TALLOC_CTX *mem_ctx,
1949 struct tevent_context *ev,
1950 struct cli_state *cli,
1951 const char *user,
1952 const char *pass, int passlen,
1953 const char *ntpass, int ntpasslen,
1954 const char *workgroup)
1956 struct tevent_req *req, *subreq;
1957 struct cli_session_setup_state *state;
1958 char *p;
1959 char *user2;
1960 uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
1962 req = tevent_req_create(mem_ctx, &state,
1963 struct cli_session_setup_state);
1964 if (req == NULL) {
1965 return NULL;
1968 if (user) {
1969 user2 = talloc_strdup(state, user);
1970 } else {
1971 user2 = talloc_strdup(state, "");
1973 if (user2 == NULL) {
1974 tevent_req_oom(req);
1975 return tevent_req_post(req, ev);
1978 if (!workgroup) {
1979 workgroup = "";
1982 /* allow for workgroups as part of the username */
1983 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
1984 (p=strchr_m(user2,*lp_winbind_separator()))) {
1985 *p = 0;
1986 user = p+1;
1987 if (!strupper_m(user2)) {
1988 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1989 return tevent_req_post(req, ev);
1991 workgroup = user2;
1994 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_LANMAN1) {
1995 tevent_req_done(req);
1996 return tevent_req_post(req, ev);
1999 /* now work out what sort of session setup we are going to
2000 do. I have split this into separate functions to make the
2001 flow a bit easier to understand (tridge) */
2003 /* if its an older server then we have to use the older request format */
2005 if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_NT1) {
2006 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
2007 DEBUG(1, ("Server requested LM password but 'client lanman auth = no'"
2008 " or 'client ntlmv2 auth = yes'\n"));
2009 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2010 return tevent_req_post(req, ev);
2013 if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
2014 !lp_client_plaintext_auth() && (*pass)) {
2015 DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
2016 " or 'client ntlmv2 auth = yes'\n"));
2017 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2018 return tevent_req_post(req, ev);
2021 subreq = cli_session_setup_lanman2_send(
2022 state, ev, cli, user, pass, passlen, workgroup);
2023 if (tevent_req_nomem(subreq, req)) {
2024 return tevent_req_post(req, ev);
2026 tevent_req_set_callback(subreq, cli_session_setup_done_lanman2,
2027 req);
2028 return req;
2031 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2032 const char *remote_realm = cli_state_remote_realm(cli);
2034 subreq = cli_session_setup_spnego_send(
2035 state, ev, cli, user, pass, workgroup, remote_realm);
2036 if (tevent_req_nomem(subreq, req)) {
2037 return tevent_req_post(req, ev);
2039 tevent_req_set_callback(subreq, cli_session_setup_done_spnego,
2040 req);
2041 return req;
2044 /* if no user is supplied then we have to do an anonymous connection.
2045 passwords are ignored */
2047 if (!user || !*user) {
2048 subreq = cli_session_setup_guest_send(state, ev, cli);
2049 if (tevent_req_nomem(subreq, req)) {
2050 return tevent_req_post(req, ev);
2052 tevent_req_set_callback(subreq, cli_session_setup_done_guest,
2053 req);
2054 return req;
2057 /* if the server is share level then send a plaintext null
2058 password at this point. The password is sent in the tree
2059 connect */
2061 if ((sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
2062 subreq = cli_session_setup_plain_send(
2063 state, ev, cli, user, "", workgroup);
2064 if (tevent_req_nomem(subreq, req)) {
2065 return tevent_req_post(req, ev);
2067 tevent_req_set_callback(subreq, cli_session_setup_done_plain,
2068 req);
2069 return req;
2072 /* if the server doesn't support encryption then we have to use
2073 plaintext. The second password is ignored */
2075 if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
2076 if (!lp_client_plaintext_auth() && (*pass)) {
2077 DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
2078 " or 'client ntlmv2 auth = yes'\n"));
2079 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2080 return tevent_req_post(req, ev);
2082 subreq = cli_session_setup_plain_send(
2083 state, ev, cli, user, pass, workgroup);
2084 if (tevent_req_nomem(subreq, req)) {
2085 return tevent_req_post(req, ev);
2087 tevent_req_set_callback(subreq, cli_session_setup_done_plain,
2088 req);
2089 return req;
2092 /* if the server supports extended security then use SPNEGO */
2094 if (smb1cli_conn_capabilities(cli->conn) & CAP_EXTENDED_SECURITY) {
2095 const char *remote_realm = cli_state_remote_realm(cli);
2097 subreq = cli_session_setup_spnego_send(
2098 state, ev, cli, user, pass, workgroup, remote_realm);
2099 if (tevent_req_nomem(subreq, req)) {
2100 return tevent_req_post(req, ev);
2102 tevent_req_set_callback(subreq, cli_session_setup_done_spnego,
2103 req);
2104 return req;
2105 } else {
2106 /* otherwise do a NT1 style session setup */
2108 subreq = cli_session_setup_nt1_send(
2109 state, ev, cli, user, pass, passlen, ntpass, ntpasslen,
2110 workgroup);
2111 if (tevent_req_nomem(subreq, req)) {
2112 return tevent_req_post(req, ev);
2114 tevent_req_set_callback(subreq, cli_session_setup_done_nt1,
2115 req);
2116 return req;
2119 tevent_req_done(req);
2120 return tevent_req_post(req, ev);
2123 static void cli_session_setup_done_lanman2(struct tevent_req *subreq)
2125 struct tevent_req *req = tevent_req_callback_data(
2126 subreq, struct tevent_req);
2127 NTSTATUS status;
2129 status = cli_session_setup_lanman2_recv(subreq);
2130 TALLOC_FREE(subreq);
2131 if (!NT_STATUS_IS_OK(status)) {
2132 tevent_req_nterror(req, status);
2133 return;
2135 tevent_req_done(req);
2138 static void cli_session_setup_done_spnego(struct tevent_req *subreq)
2140 struct tevent_req *req = tevent_req_callback_data(
2141 subreq, struct tevent_req);
2142 ADS_STATUS status;
2144 status = cli_session_setup_spnego_recv(subreq);
2145 TALLOC_FREE(subreq);
2146 if (!ADS_ERR_OK(status)) {
2147 DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
2148 tevent_req_nterror(req, ads_ntstatus(status));
2149 return;
2151 tevent_req_done(req);
2154 static void cli_session_setup_done_guest(struct tevent_req *subreq)
2156 struct tevent_req *req = tevent_req_callback_data(
2157 subreq, struct tevent_req);
2158 NTSTATUS status;
2160 status = cli_session_setup_guest_recv(subreq);
2161 TALLOC_FREE(subreq);
2162 if (!NT_STATUS_IS_OK(status)) {
2163 tevent_req_nterror(req, status);
2164 return;
2166 tevent_req_done(req);
2169 static void cli_session_setup_done_plain(struct tevent_req *subreq)
2171 struct tevent_req *req = tevent_req_callback_data(
2172 subreq, struct tevent_req);
2173 NTSTATUS status;
2175 status = cli_session_setup_plain_recv(subreq);
2176 TALLOC_FREE(subreq);
2177 if (!NT_STATUS_IS_OK(status)) {
2178 tevent_req_nterror(req, status);
2179 return;
2181 tevent_req_done(req);
2184 static void cli_session_setup_done_nt1(struct tevent_req *subreq)
2186 struct tevent_req *req = tevent_req_callback_data(
2187 subreq, struct tevent_req);
2188 NTSTATUS status;
2190 status = cli_session_setup_nt1_recv(subreq);
2191 TALLOC_FREE(subreq);
2192 if (!NT_STATUS_IS_OK(status)) {
2193 DEBUG(3, ("cli_session_setup: NT1 session setup "
2194 "failed: %s\n", nt_errstr(status)));
2195 tevent_req_nterror(req, status);
2196 return;
2198 tevent_req_done(req);
2201 NTSTATUS cli_session_setup_recv(struct tevent_req *req)
2203 return tevent_req_simple_recv_ntstatus(req);
2206 NTSTATUS cli_session_setup(struct cli_state *cli,
2207 const char *user,
2208 const char *pass, int passlen,
2209 const char *ntpass, int ntpasslen,
2210 const char *workgroup)
2212 struct tevent_context *ev;
2213 struct tevent_req *req;
2214 NTSTATUS status = NT_STATUS_NO_MEMORY;
2216 if (smbXcli_conn_has_async_calls(cli->conn)) {
2217 return NT_STATUS_INVALID_PARAMETER;
2219 ev = samba_tevent_context_init(talloc_tos());
2220 if (ev == NULL) {
2221 goto fail;
2223 req = cli_session_setup_send(ev, ev, cli, user, pass, passlen,
2224 ntpass, ntpasslen, workgroup);
2225 if (req == NULL) {
2226 goto fail;
2228 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2229 goto fail;
2231 status = cli_session_setup_recv(req);
2232 fail:
2233 TALLOC_FREE(ev);
2234 return status;
2237 /****************************************************************************
2238 Send a uloggoff.
2239 *****************************************************************************/
2241 struct cli_ulogoff_state {
2242 struct cli_state *cli;
2243 uint16_t vwv[3];
2246 static void cli_ulogoff_done(struct tevent_req *subreq);
2248 static struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx,
2249 struct tevent_context *ev,
2250 struct cli_state *cli)
2252 struct tevent_req *req, *subreq;
2253 struct cli_ulogoff_state *state;
2255 req = tevent_req_create(mem_ctx, &state, struct cli_ulogoff_state);
2256 if (req == NULL) {
2257 return NULL;
2259 state->cli = cli;
2261 SCVAL(state->vwv+0, 0, 0xFF);
2262 SCVAL(state->vwv+1, 0, 0);
2263 SSVAL(state->vwv+2, 0, 0);
2265 subreq = cli_smb_send(state, ev, cli, SMBulogoffX, 0, 2, state->vwv,
2266 0, NULL);
2267 if (tevent_req_nomem(subreq, req)) {
2268 return tevent_req_post(req, ev);
2270 tevent_req_set_callback(subreq, cli_ulogoff_done, req);
2271 return req;
2274 static void cli_ulogoff_done(struct tevent_req *subreq)
2276 struct tevent_req *req = tevent_req_callback_data(
2277 subreq, struct tevent_req);
2278 struct cli_ulogoff_state *state = tevent_req_data(
2279 req, struct cli_ulogoff_state);
2280 NTSTATUS status;
2282 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2283 if (!NT_STATUS_IS_OK(status)) {
2284 tevent_req_nterror(req, status);
2285 return;
2287 cli_state_set_uid(state->cli, UID_FIELD_INVALID);
2288 tevent_req_done(req);
2291 static NTSTATUS cli_ulogoff_recv(struct tevent_req *req)
2293 return tevent_req_simple_recv_ntstatus(req);
2296 NTSTATUS cli_ulogoff(struct cli_state *cli)
2298 struct tevent_context *ev;
2299 struct tevent_req *req;
2300 NTSTATUS status = NT_STATUS_NO_MEMORY;
2302 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2303 status = smb2cli_logoff(cli->conn,
2304 cli->timeout,
2305 cli->smb2.session);
2306 if (!NT_STATUS_IS_OK(status)) {
2307 return status;
2309 smb2cli_session_set_id_and_flags(cli->smb2.session,
2310 UINT64_MAX, 0);
2311 return NT_STATUS_OK;
2314 if (smbXcli_conn_has_async_calls(cli->conn)) {
2315 return NT_STATUS_INVALID_PARAMETER;
2317 ev = samba_tevent_context_init(talloc_tos());
2318 if (ev == NULL) {
2319 goto fail;
2321 req = cli_ulogoff_send(ev, ev, cli);
2322 if (req == NULL) {
2323 goto fail;
2325 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2326 goto fail;
2328 status = cli_ulogoff_recv(req);
2329 fail:
2330 TALLOC_FREE(ev);
2331 return status;
2334 /****************************************************************************
2335 Send a tconX.
2336 ****************************************************************************/
2338 struct cli_tcon_andx_state {
2339 struct cli_state *cli;
2340 uint16_t vwv[4];
2341 struct iovec bytes;
2344 static void cli_tcon_andx_done(struct tevent_req *subreq);
2346 struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
2347 struct tevent_context *ev,
2348 struct cli_state *cli,
2349 const char *share, const char *dev,
2350 const char *pass, int passlen,
2351 struct tevent_req **psmbreq)
2353 struct tevent_req *req, *subreq;
2354 struct cli_tcon_andx_state *state;
2355 uint8_t p24[24];
2356 uint16_t *vwv;
2357 char *tmp = NULL;
2358 uint8_t *bytes;
2359 uint16_t sec_mode = smb1cli_conn_server_security_mode(cli->conn);
2360 uint16_t tcon_flags = 0;
2362 *psmbreq = NULL;
2364 req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state);
2365 if (req == NULL) {
2366 return NULL;
2368 state->cli = cli;
2369 vwv = state->vwv;
2371 cli->share = talloc_strdup(cli, share);
2372 if (!cli->share) {
2373 return NULL;
2376 /* in user level security don't send a password now */
2377 if (sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
2378 passlen = 1;
2379 pass = "";
2380 } else if (pass == NULL) {
2381 DEBUG(1, ("Server not using user level security and no "
2382 "password supplied.\n"));
2383 goto access_denied;
2386 if ((sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
2387 *pass && passlen != 24) {
2388 if (!lp_client_lanman_auth()) {
2389 DEBUG(1, ("Server requested LANMAN password "
2390 "(share-level security) but "
2391 "'client lanman auth = no' or 'client ntlmv2 auth = yes'\n"));
2392 goto access_denied;
2396 * Non-encrypted passwords - convert to DOS codepage before
2397 * encryption.
2399 SMBencrypt(pass, smb1cli_conn_server_challenge(cli->conn), p24);
2400 passlen = 24;
2401 pass = (const char *)p24;
2402 } else {
2403 if((sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
2404 |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
2405 == 0) {
2406 uint8_t *tmp_pass;
2408 if (!lp_client_plaintext_auth() && (*pass)) {
2409 DEBUG(1, ("Server requested PLAINTEXT "
2410 "password but "
2411 "'client plaintext auth = no' or 'client ntlmv2 auth = yes'\n"));
2412 goto access_denied;
2416 * Non-encrypted passwords - convert to DOS codepage
2417 * before using.
2419 tmp_pass = talloc_array(talloc_tos(), uint8, 0);
2420 if (tevent_req_nomem(tmp_pass, req)) {
2421 return tevent_req_post(req, ev);
2423 tmp_pass = trans2_bytes_push_str(tmp_pass,
2424 false, /* always DOS */
2425 pass,
2426 passlen,
2427 NULL);
2428 if (tevent_req_nomem(tmp_pass, req)) {
2429 return tevent_req_post(req, ev);
2431 pass = (const char *)tmp_pass;
2432 passlen = talloc_get_size(tmp_pass);
2436 tcon_flags |= TCONX_FLAG_EXTENDED_RESPONSE;
2437 tcon_flags |= TCONX_FLAG_EXTENDED_SIGNATURES;
2439 SCVAL(vwv+0, 0, 0xFF);
2440 SCVAL(vwv+0, 1, 0);
2441 SSVAL(vwv+1, 0, 0);
2442 SSVAL(vwv+2, 0, tcon_flags);
2443 SSVAL(vwv+3, 0, passlen);
2445 if (passlen && pass) {
2446 bytes = (uint8_t *)talloc_memdup(state, pass, passlen);
2447 } else {
2448 bytes = talloc_array(state, uint8_t, 0);
2452 * Add the sharename
2454 tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
2455 smbXcli_conn_remote_name(cli->conn), share);
2456 if (tmp == NULL) {
2457 TALLOC_FREE(req);
2458 return NULL;
2460 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn), tmp, strlen(tmp)+1,
2461 NULL);
2462 TALLOC_FREE(tmp);
2465 * Add the devicetype
2467 tmp = talloc_strdup_upper(talloc_tos(), dev);
2468 if (tmp == NULL) {
2469 TALLOC_FREE(req);
2470 return NULL;
2472 bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
2473 TALLOC_FREE(tmp);
2475 if (bytes == NULL) {
2476 TALLOC_FREE(req);
2477 return NULL;
2480 state->bytes.iov_base = (void *)bytes;
2481 state->bytes.iov_len = talloc_get_size(bytes);
2483 subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
2484 1, &state->bytes);
2485 if (subreq == NULL) {
2486 TALLOC_FREE(req);
2487 return NULL;
2489 tevent_req_set_callback(subreq, cli_tcon_andx_done, req);
2490 *psmbreq = subreq;
2491 return req;
2493 access_denied:
2494 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
2495 return tevent_req_post(req, ev);
2498 struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
2499 struct tevent_context *ev,
2500 struct cli_state *cli,
2501 const char *share, const char *dev,
2502 const char *pass, int passlen)
2504 struct tevent_req *req, *subreq;
2505 NTSTATUS status;
2507 req = cli_tcon_andx_create(mem_ctx, ev, cli, share, dev, pass, passlen,
2508 &subreq);
2509 if (req == NULL) {
2510 return NULL;
2512 if (subreq == NULL) {
2513 return req;
2515 status = smb1cli_req_chain_submit(&subreq, 1);
2516 if (!NT_STATUS_IS_OK(status)) {
2517 tevent_req_nterror(req, status);
2518 return tevent_req_post(req, ev);
2520 return req;
2523 static void cli_tcon_andx_done(struct tevent_req *subreq)
2525 struct tevent_req *req = tevent_req_callback_data(
2526 subreq, struct tevent_req);
2527 struct cli_tcon_andx_state *state = tevent_req_data(
2528 req, struct cli_tcon_andx_state);
2529 struct cli_state *cli = state->cli;
2530 uint8_t *in;
2531 uint8_t *inhdr;
2532 uint8_t wct;
2533 uint16_t *vwv;
2534 uint32_t num_bytes;
2535 uint8_t *bytes;
2536 NTSTATUS status;
2537 uint16_t optional_support = 0;
2539 status = cli_smb_recv(subreq, state, &in, 0, &wct, &vwv,
2540 &num_bytes, &bytes);
2541 TALLOC_FREE(subreq);
2542 if (!NT_STATUS_IS_OK(status)) {
2543 tevent_req_nterror(req, status);
2544 return;
2547 inhdr = in + NBT_HDR_SIZE;
2549 if (num_bytes) {
2550 if (clistr_pull_talloc(cli,
2551 (const char *)inhdr,
2552 SVAL(inhdr, HDR_FLG2),
2553 &cli->dev,
2554 bytes,
2555 num_bytes,
2556 STR_TERMINATE|STR_ASCII) == -1) {
2557 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2558 return;
2560 } else {
2561 cli->dev = talloc_strdup(cli, "");
2562 if (cli->dev == NULL) {
2563 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
2564 return;
2568 if ((smbXcli_conn_protocol(cli->conn) >= PROTOCOL_NT1) && (num_bytes == 3)) {
2569 /* almost certainly win95 - enable bug fixes */
2570 cli->win95 = True;
2574 * Make sure that we have the optional support 16-bit field. WCT > 2.
2575 * Avoids issues when connecting to Win9x boxes sharing files
2578 if ((wct > 2) && (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_LANMAN2)) {
2579 optional_support = SVAL(vwv+2, 0);
2582 if (optional_support & SMB_EXTENDED_SIGNATURES) {
2583 smb1cli_session_protect_session_key(cli->smb1.session);
2586 smb1cli_tcon_set_values(state->cli->smb1.tcon,
2587 SVAL(inhdr, HDR_TID),
2588 optional_support,
2589 0, /* maximal_access */
2590 0, /* guest_maximal_access */
2591 NULL, /* service */
2592 NULL); /* fs_type */
2594 tevent_req_done(req);
2597 NTSTATUS cli_tcon_andx_recv(struct tevent_req *req)
2599 return tevent_req_simple_recv_ntstatus(req);
2602 NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
2603 const char *dev, const char *pass, int passlen)
2605 TALLOC_CTX *frame = talloc_stackframe();
2606 struct tevent_context *ev;
2607 struct tevent_req *req;
2608 NTSTATUS status = NT_STATUS_NO_MEMORY;
2610 if (smbXcli_conn_has_async_calls(cli->conn)) {
2612 * Can't use sync call while an async call is in flight
2614 status = NT_STATUS_INVALID_PARAMETER;
2615 goto fail;
2618 ev = samba_tevent_context_init(frame);
2619 if (ev == NULL) {
2620 goto fail;
2623 req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
2624 if (req == NULL) {
2625 goto fail;
2628 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2629 goto fail;
2632 status = cli_tcon_andx_recv(req);
2633 fail:
2634 TALLOC_FREE(frame);
2635 return status;
2638 struct cli_tree_connect_state {
2639 struct cli_state *cli;
2642 static struct tevent_req *cli_raw_tcon_send(
2643 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
2644 const char *service, const char *pass, const char *dev);
2645 static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
2646 uint16 *max_xmit, uint16 *tid);
2648 static void cli_tree_connect_smb2_done(struct tevent_req *subreq);
2649 static void cli_tree_connect_andx_done(struct tevent_req *subreq);
2650 static void cli_tree_connect_raw_done(struct tevent_req *subreq);
2652 static struct tevent_req *cli_tree_connect_send(
2653 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
2654 const char *share, const char *dev, const char *pass, int passlen)
2656 struct tevent_req *req, *subreq;
2657 struct cli_tree_connect_state *state;
2659 req = tevent_req_create(mem_ctx, &state,
2660 struct cli_tree_connect_state);
2661 if (req == NULL) {
2662 return NULL;
2664 state->cli = cli;
2666 cli->share = talloc_strdup(cli, share);
2667 if (tevent_req_nomem(cli->share, req)) {
2668 return tevent_req_post(req, ev);
2671 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2672 subreq = smb2cli_tcon_send(state, ev, cli, share);
2673 if (tevent_req_nomem(subreq, req)) {
2674 return tevent_req_post(req, ev);
2676 tevent_req_set_callback(subreq, cli_tree_connect_smb2_done,
2677 req);
2678 return req;
2681 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_LANMAN1) {
2682 subreq = cli_tcon_andx_send(state, ev, cli, share, dev,
2683 pass, passlen);
2684 if (tevent_req_nomem(subreq, req)) {
2685 return tevent_req_post(req, ev);
2687 tevent_req_set_callback(subreq, cli_tree_connect_andx_done,
2688 req);
2689 return req;
2692 subreq = cli_raw_tcon_send(state, ev, cli, share, pass, dev);
2693 if (tevent_req_nomem(subreq, req)) {
2694 return tevent_req_post(req, ev);
2696 tevent_req_set_callback(subreq, cli_tree_connect_raw_done, req);
2698 return req;
2701 static void cli_tree_connect_smb2_done(struct tevent_req *subreq)
2703 tevent_req_simple_finish_ntstatus(
2704 subreq, smb2cli_tcon_recv(subreq));
2707 static void cli_tree_connect_andx_done(struct tevent_req *subreq)
2709 tevent_req_simple_finish_ntstatus(
2710 subreq, cli_tcon_andx_recv(subreq));
2713 static void cli_tree_connect_raw_done(struct tevent_req *subreq)
2715 struct tevent_req *req = tevent_req_callback_data(
2716 subreq, struct tevent_req);
2717 struct cli_tree_connect_state *state = tevent_req_data(
2718 req, struct cli_tree_connect_state);
2719 NTSTATUS status;
2720 uint16_t max_xmit = 0;
2721 uint16_t tid = 0;
2723 status = cli_raw_tcon_recv(subreq, &max_xmit, &tid);
2724 if (tevent_req_nterror(req, status)) {
2725 return;
2728 smb1cli_tcon_set_values(state->cli->smb1.tcon,
2729 tid,
2730 0, /* optional_support */
2731 0, /* maximal_access */
2732 0, /* guest_maximal_access */
2733 NULL, /* service */
2734 NULL); /* fs_type */
2736 tevent_req_done(req);
2739 static NTSTATUS cli_tree_connect_recv(struct tevent_req *req)
2741 return tevent_req_simple_recv_ntstatus(req);
2744 NTSTATUS cli_tree_connect(struct cli_state *cli, const char *share,
2745 const char *dev, const char *pass, int passlen)
2747 struct tevent_context *ev;
2748 struct tevent_req *req;
2749 NTSTATUS status = NT_STATUS_NO_MEMORY;
2751 if (smbXcli_conn_has_async_calls(cli->conn)) {
2752 return NT_STATUS_INVALID_PARAMETER;
2754 ev = samba_tevent_context_init(talloc_tos());
2755 if (ev == NULL) {
2756 goto fail;
2758 req = cli_tree_connect_send(ev, ev, cli, share, dev, pass, passlen);
2759 if (req == NULL) {
2760 goto fail;
2762 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2763 goto fail;
2765 status = cli_tree_connect_recv(req);
2766 fail:
2767 TALLOC_FREE(ev);
2768 return status;
2771 /****************************************************************************
2772 Send a tree disconnect.
2773 ****************************************************************************/
2775 struct cli_tdis_state {
2776 struct cli_state *cli;
2779 static void cli_tdis_done(struct tevent_req *subreq);
2781 static struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx,
2782 struct tevent_context *ev,
2783 struct cli_state *cli)
2785 struct tevent_req *req, *subreq;
2786 struct cli_tdis_state *state;
2788 req = tevent_req_create(mem_ctx, &state, struct cli_tdis_state);
2789 if (req == NULL) {
2790 return NULL;
2792 state->cli = cli;
2794 subreq = cli_smb_send(state, ev, cli, SMBtdis, 0, 0, NULL, 0, NULL);
2795 if (tevent_req_nomem(subreq, req)) {
2796 return tevent_req_post(req, ev);
2798 tevent_req_set_callback(subreq, cli_tdis_done, req);
2799 return req;
2802 static void cli_tdis_done(struct tevent_req *subreq)
2804 struct tevent_req *req = tevent_req_callback_data(
2805 subreq, struct tevent_req);
2806 struct cli_tdis_state *state = tevent_req_data(
2807 req, struct cli_tdis_state);
2808 NTSTATUS status;
2810 status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
2811 TALLOC_FREE(subreq);
2812 if (!NT_STATUS_IS_OK(status)) {
2813 tevent_req_nterror(req, status);
2814 return;
2816 cli_state_set_tid(state->cli, UINT16_MAX);
2817 tevent_req_done(req);
2820 static NTSTATUS cli_tdis_recv(struct tevent_req *req)
2822 return tevent_req_simple_recv_ntstatus(req);
2825 NTSTATUS cli_tdis(struct cli_state *cli)
2827 struct tevent_context *ev;
2828 struct tevent_req *req;
2829 NTSTATUS status = NT_STATUS_NO_MEMORY;
2831 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
2832 return smb2cli_tdis(cli);
2835 if (smbXcli_conn_has_async_calls(cli->conn)) {
2836 return NT_STATUS_INVALID_PARAMETER;
2838 ev = samba_tevent_context_init(talloc_tos());
2839 if (ev == NULL) {
2840 goto fail;
2842 req = cli_tdis_send(ev, ev, cli);
2843 if (req == NULL) {
2844 goto fail;
2846 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2847 goto fail;
2849 status = cli_tdis_recv(req);
2850 fail:
2851 TALLOC_FREE(ev);
2852 return status;
2855 struct cli_connect_sock_state {
2856 const char **called_names;
2857 const char **calling_names;
2858 int *called_types;
2859 int fd;
2860 uint16_t port;
2863 static void cli_connect_sock_done(struct tevent_req *subreq);
2866 * Async only if we don't have to look up the name, i.e. "pss" is set with a
2867 * nonzero address.
2870 static struct tevent_req *cli_connect_sock_send(
2871 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2872 const char *host, int name_type, const struct sockaddr_storage *pss,
2873 const char *myname, uint16_t port)
2875 struct tevent_req *req, *subreq;
2876 struct cli_connect_sock_state *state;
2877 const char *prog;
2878 unsigned i, num_addrs;
2879 NTSTATUS status;
2881 req = tevent_req_create(mem_ctx, &state,
2882 struct cli_connect_sock_state);
2883 if (req == NULL) {
2884 return NULL;
2887 prog = getenv("LIBSMB_PROG");
2888 if (prog != NULL) {
2889 state->fd = sock_exec(prog);
2890 if (state->fd == -1) {
2891 status = map_nt_error_from_unix(errno);
2892 tevent_req_nterror(req, status);
2893 } else {
2894 state->port = 0;
2895 tevent_req_done(req);
2897 return tevent_req_post(req, ev);
2900 if ((pss == NULL) || is_zero_addr(pss)) {
2901 struct sockaddr_storage *addrs;
2904 * Here we cheat. resolve_name_list is not async at all. So
2905 * this call will only be really async if the name lookup has
2906 * been done externally.
2909 status = resolve_name_list(state, host, name_type,
2910 &addrs, &num_addrs);
2911 if (!NT_STATUS_IS_OK(status)) {
2912 tevent_req_nterror(req, status);
2913 return tevent_req_post(req, ev);
2915 pss = addrs;
2916 } else {
2917 num_addrs = 1;
2920 state->called_names = talloc_array(state, const char *, num_addrs);
2921 if (tevent_req_nomem(state->called_names, req)) {
2922 return tevent_req_post(req, ev);
2924 state->called_types = talloc_array(state, int, num_addrs);
2925 if (tevent_req_nomem(state->called_types, req)) {
2926 return tevent_req_post(req, ev);
2928 state->calling_names = talloc_array(state, const char *, num_addrs);
2929 if (tevent_req_nomem(state->calling_names, req)) {
2930 return tevent_req_post(req, ev);
2932 for (i=0; i<num_addrs; i++) {
2933 state->called_names[i] = host;
2934 state->called_types[i] = name_type;
2935 state->calling_names[i] = myname;
2938 subreq = smbsock_any_connect_send(
2939 state, ev, pss, state->called_names, state->called_types,
2940 state->calling_names, NULL, num_addrs, port);
2941 if (tevent_req_nomem(subreq, req)) {
2942 return tevent_req_post(req, ev);
2944 tevent_req_set_callback(subreq, cli_connect_sock_done, req);
2945 return req;
2948 static void cli_connect_sock_done(struct tevent_req *subreq)
2950 struct tevent_req *req = tevent_req_callback_data(
2951 subreq, struct tevent_req);
2952 struct cli_connect_sock_state *state = tevent_req_data(
2953 req, struct cli_connect_sock_state);
2954 NTSTATUS status;
2956 status = smbsock_any_connect_recv(subreq, &state->fd, NULL,
2957 &state->port);
2958 TALLOC_FREE(subreq);
2959 if (tevent_req_nterror(req, status)) {
2960 return;
2962 set_socket_options(state->fd, lp_socket_options());
2963 tevent_req_done(req);
2966 static NTSTATUS cli_connect_sock_recv(struct tevent_req *req,
2967 int *pfd, uint16_t *pport)
2969 struct cli_connect_sock_state *state = tevent_req_data(
2970 req, struct cli_connect_sock_state);
2971 NTSTATUS status;
2973 if (tevent_req_is_nterror(req, &status)) {
2974 return status;
2976 *pfd = state->fd;
2977 *pport = state->port;
2978 return NT_STATUS_OK;
2981 struct cli_connect_nb_state {
2982 const char *desthost;
2983 int signing_state;
2984 int flags;
2985 struct cli_state *cli;
2988 static void cli_connect_nb_done(struct tevent_req *subreq);
2990 static struct tevent_req *cli_connect_nb_send(
2991 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
2992 const char *host, const struct sockaddr_storage *dest_ss,
2993 uint16_t port, int name_type, const char *myname,
2994 int signing_state, int flags)
2996 struct tevent_req *req, *subreq;
2997 struct cli_connect_nb_state *state;
2998 char *p;
3000 req = tevent_req_create(mem_ctx, &state, struct cli_connect_nb_state);
3001 if (req == NULL) {
3002 return NULL;
3004 state->desthost = host;
3005 state->signing_state = signing_state;
3006 state->flags = flags;
3008 p = strchr(host, '#');
3009 if (p != NULL) {
3010 name_type = strtol(p+1, NULL, 16);
3011 host = talloc_strndup(state, host, p - host);
3012 if (tevent_req_nomem(host, req)) {
3013 return tevent_req_post(req, ev);
3017 subreq = cli_connect_sock_send(state, ev, host, name_type, dest_ss,
3018 myname, port);
3019 if (tevent_req_nomem(subreq, req)) {
3020 return tevent_req_post(req, ev);
3022 tevent_req_set_callback(subreq, cli_connect_nb_done, req);
3023 return req;
3026 static void cli_connect_nb_done(struct tevent_req *subreq)
3028 struct tevent_req *req = tevent_req_callback_data(
3029 subreq, struct tevent_req);
3030 struct cli_connect_nb_state *state = tevent_req_data(
3031 req, struct cli_connect_nb_state);
3032 NTSTATUS status;
3033 int fd;
3034 uint16_t port;
3036 status = cli_connect_sock_recv(subreq, &fd, &port);
3037 TALLOC_FREE(subreq);
3038 if (tevent_req_nterror(req, status)) {
3039 return;
3042 state->cli = cli_state_create(state, fd, state->desthost, NULL,
3043 state->signing_state, state->flags);
3044 if (tevent_req_nomem(state->cli, req)) {
3045 close(fd);
3046 return;
3048 tevent_req_done(req);
3051 static NTSTATUS cli_connect_nb_recv(struct tevent_req *req,
3052 struct cli_state **pcli)
3054 struct cli_connect_nb_state *state = tevent_req_data(
3055 req, struct cli_connect_nb_state);
3056 NTSTATUS status;
3058 if (tevent_req_is_nterror(req, &status)) {
3059 return status;
3061 *pcli = talloc_move(NULL, &state->cli);
3062 return NT_STATUS_OK;
3065 NTSTATUS cli_connect_nb(const char *host, const struct sockaddr_storage *dest_ss,
3066 uint16_t port, int name_type, const char *myname,
3067 int signing_state, int flags, struct cli_state **pcli)
3069 struct tevent_context *ev;
3070 struct tevent_req *req;
3071 NTSTATUS status = NT_STATUS_NO_MEMORY;
3073 ev = samba_tevent_context_init(talloc_tos());
3074 if (ev == NULL) {
3075 goto fail;
3077 req = cli_connect_nb_send(ev, ev, host, dest_ss, port, name_type,
3078 myname, signing_state, flags);
3079 if (req == NULL) {
3080 goto fail;
3082 if (!tevent_req_set_endtime(req, ev, timeval_current_ofs(20, 0))) {
3083 goto fail;
3085 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3086 goto fail;
3088 status = cli_connect_nb_recv(req, pcli);
3089 fail:
3090 TALLOC_FREE(ev);
3091 return status;
3094 struct cli_start_connection_state {
3095 struct tevent_context *ev;
3096 struct cli_state *cli;
3099 static void cli_start_connection_connected(struct tevent_req *subreq);
3100 static void cli_start_connection_done(struct tevent_req *subreq);
3103 establishes a connection to after the negprot.
3104 @param output_cli A fully initialised cli structure, non-null only on success
3105 @param dest_host The netbios name of the remote host
3106 @param dest_ss (optional) The the destination IP, NULL for name based lookup
3107 @param port (optional) The destination port (0 for default)
3110 static struct tevent_req *cli_start_connection_send(
3111 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3112 const char *my_name, const char *dest_host,
3113 const struct sockaddr_storage *dest_ss, int port,
3114 int signing_state, int flags)
3116 struct tevent_req *req, *subreq;
3117 struct cli_start_connection_state *state;
3119 req = tevent_req_create(mem_ctx, &state,
3120 struct cli_start_connection_state);
3121 if (req == NULL) {
3122 return NULL;
3124 state->ev = ev;
3126 subreq = cli_connect_nb_send(state, ev, dest_host, dest_ss, port,
3127 0x20, my_name, signing_state, flags);
3128 if (tevent_req_nomem(subreq, req)) {
3129 return tevent_req_post(req, ev);
3131 tevent_req_set_callback(subreq, cli_start_connection_connected, req);
3132 return req;
3135 static void cli_start_connection_connected(struct tevent_req *subreq)
3137 struct tevent_req *req = tevent_req_callback_data(
3138 subreq, struct tevent_req);
3139 struct cli_start_connection_state *state = tevent_req_data(
3140 req, struct cli_start_connection_state);
3141 NTSTATUS status;
3143 status = cli_connect_nb_recv(subreq, &state->cli);
3144 TALLOC_FREE(subreq);
3145 if (tevent_req_nterror(req, status)) {
3146 return;
3149 subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn,
3150 state->cli->timeout,
3151 lp_cli_minprotocol(),
3152 lp_cli_maxprotocol());
3153 if (tevent_req_nomem(subreq, req)) {
3154 return;
3156 tevent_req_set_callback(subreq, cli_start_connection_done, req);
3159 static void cli_start_connection_done(struct tevent_req *subreq)
3161 struct tevent_req *req = tevent_req_callback_data(
3162 subreq, struct tevent_req);
3163 struct cli_start_connection_state *state = tevent_req_data(
3164 req, struct cli_start_connection_state);
3165 NTSTATUS status;
3167 status = smbXcli_negprot_recv(subreq);
3168 TALLOC_FREE(subreq);
3169 if (tevent_req_nterror(req, status)) {
3170 return;
3173 if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
3174 /* Ensure we ask for some initial credits. */
3175 smb2cli_conn_set_max_credits(state->cli->conn,
3176 DEFAULT_SMB2_MAX_CREDITS);
3179 tevent_req_done(req);
3182 static NTSTATUS cli_start_connection_recv(struct tevent_req *req,
3183 struct cli_state **output_cli)
3185 struct cli_start_connection_state *state = tevent_req_data(
3186 req, struct cli_start_connection_state);
3187 NTSTATUS status;
3189 if (tevent_req_is_nterror(req, &status)) {
3190 return status;
3192 *output_cli = state->cli;
3194 return NT_STATUS_OK;
3197 NTSTATUS cli_start_connection(struct cli_state **output_cli,
3198 const char *my_name,
3199 const char *dest_host,
3200 const struct sockaddr_storage *dest_ss, int port,
3201 int signing_state, int flags)
3203 struct tevent_context *ev;
3204 struct tevent_req *req;
3205 NTSTATUS status = NT_STATUS_NO_MEMORY;
3207 ev = samba_tevent_context_init(talloc_tos());
3208 if (ev == NULL) {
3209 goto fail;
3211 req = cli_start_connection_send(ev, ev, my_name, dest_host, dest_ss,
3212 port, signing_state, flags);
3213 if (req == NULL) {
3214 goto fail;
3216 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3217 goto fail;
3219 status = cli_start_connection_recv(req, output_cli);
3220 fail:
3221 TALLOC_FREE(ev);
3222 return status;
3226 establishes a connection right up to doing tconX, password specified.
3227 @param output_cli A fully initialised cli structure, non-null only on success
3228 @param dest_host The netbios name of the remote host
3229 @param dest_ip (optional) The the destination IP, NULL for name based lookup
3230 @param port (optional) The destination port (0 for default)
3231 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
3232 @param service_type The 'type' of serivice.
3233 @param user Username, unix string
3234 @param domain User's domain
3235 @param password User's password, unencrypted unix string.
3238 struct cli_full_connection_state {
3239 struct tevent_context *ev;
3240 const char *service;
3241 const char *service_type;
3242 const char *user;
3243 const char *domain;
3244 const char *password;
3245 int pw_len;
3246 int flags;
3247 struct cli_state *cli;
3250 static int cli_full_connection_state_destructor(
3251 struct cli_full_connection_state *s);
3252 static void cli_full_connection_started(struct tevent_req *subreq);
3253 static void cli_full_connection_sess_set_up(struct tevent_req *subreq);
3254 static void cli_full_connection_done(struct tevent_req *subreq);
3256 struct tevent_req *cli_full_connection_send(
3257 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
3258 const char *my_name, const char *dest_host,
3259 const struct sockaddr_storage *dest_ss, int port,
3260 const char *service, const char *service_type,
3261 const char *user, const char *domain,
3262 const char *password, int flags, int signing_state)
3264 struct tevent_req *req, *subreq;
3265 struct cli_full_connection_state *state;
3267 req = tevent_req_create(mem_ctx, &state,
3268 struct cli_full_connection_state);
3269 if (req == NULL) {
3270 return NULL;
3272 talloc_set_destructor(state, cli_full_connection_state_destructor);
3274 state->ev = ev;
3275 state->service = service;
3276 state->service_type = service_type;
3277 state->user = user;
3278 state->domain = domain;
3279 state->password = password;
3280 state->flags = flags;
3282 state->pw_len = state->password ? strlen(state->password)+1 : 0;
3283 if (state->password == NULL) {
3284 state->password = "";
3287 subreq = cli_start_connection_send(
3288 state, ev, my_name, dest_host, dest_ss, port,
3289 signing_state, flags);
3290 if (tevent_req_nomem(subreq, req)) {
3291 return tevent_req_post(req, ev);
3293 tevent_req_set_callback(subreq, cli_full_connection_started, req);
3294 return req;
3297 static int cli_full_connection_state_destructor(
3298 struct cli_full_connection_state *s)
3300 if (s->cli != NULL) {
3301 cli_shutdown(s->cli);
3302 s->cli = NULL;
3304 return 0;
3307 static void cli_full_connection_started(struct tevent_req *subreq)
3309 struct tevent_req *req = tevent_req_callback_data(
3310 subreq, struct tevent_req);
3311 struct cli_full_connection_state *state = tevent_req_data(
3312 req, struct cli_full_connection_state);
3313 NTSTATUS status;
3315 status = cli_start_connection_recv(subreq, &state->cli);
3316 TALLOC_FREE(subreq);
3317 if (tevent_req_nterror(req, status)) {
3318 return;
3320 subreq = cli_session_setup_send(
3321 state, state->ev, state->cli, state->user,
3322 state->password, state->pw_len, state->password, state->pw_len,
3323 state->domain);
3324 if (tevent_req_nomem(subreq, req)) {
3325 return;
3327 tevent_req_set_callback(subreq, cli_full_connection_sess_set_up, req);
3330 static void cli_full_connection_sess_set_up(struct tevent_req *subreq)
3332 struct tevent_req *req = tevent_req_callback_data(
3333 subreq, struct tevent_req);
3334 struct cli_full_connection_state *state = tevent_req_data(
3335 req, struct cli_full_connection_state);
3336 NTSTATUS status;
3338 status = cli_session_setup_recv(subreq);
3339 TALLOC_FREE(subreq);
3341 if (!NT_STATUS_IS_OK(status) &&
3342 (state->flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
3344 state->flags &= ~CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
3346 subreq = cli_session_setup_send(
3347 state, state->ev, state->cli, "", "", 0, "", 0,
3348 state->domain);
3349 if (tevent_req_nomem(subreq, req)) {
3350 return;
3352 tevent_req_set_callback(
3353 subreq, cli_full_connection_sess_set_up, req);
3354 return;
3357 if (tevent_req_nterror(req, status)) {
3358 return;
3361 if (state->service != NULL) {
3362 subreq = cli_tree_connect_send(
3363 state, state->ev, state->cli,
3364 state->service, state->service_type,
3365 state->password, state->pw_len);
3366 if (tevent_req_nomem(subreq, req)) {
3367 return;
3369 tevent_req_set_callback(subreq, cli_full_connection_done, req);
3370 return;
3373 status = cli_init_creds(state->cli, state->user, state->domain,
3374 state->password);
3375 if (tevent_req_nterror(req, status)) {
3376 return;
3378 tevent_req_done(req);
3381 static void cli_full_connection_done(struct tevent_req *subreq)
3383 struct tevent_req *req = tevent_req_callback_data(
3384 subreq, struct tevent_req);
3385 struct cli_full_connection_state *state = tevent_req_data(
3386 req, struct cli_full_connection_state);
3387 NTSTATUS status;
3389 status = cli_tree_connect_recv(subreq);
3390 TALLOC_FREE(subreq);
3391 if (tevent_req_nterror(req, status)) {
3392 return;
3394 status = cli_init_creds(state->cli, state->user, state->domain,
3395 state->password);
3396 if (tevent_req_nterror(req, status)) {
3397 return;
3399 tevent_req_done(req);
3402 NTSTATUS cli_full_connection_recv(struct tevent_req *req,
3403 struct cli_state **output_cli)
3405 struct cli_full_connection_state *state = tevent_req_data(
3406 req, struct cli_full_connection_state);
3407 NTSTATUS status;
3409 if (tevent_req_is_nterror(req, &status)) {
3410 return status;
3412 *output_cli = state->cli;
3413 talloc_set_destructor(state, NULL);
3414 return NT_STATUS_OK;
3417 NTSTATUS cli_full_connection(struct cli_state **output_cli,
3418 const char *my_name,
3419 const char *dest_host,
3420 const struct sockaddr_storage *dest_ss, int port,
3421 const char *service, const char *service_type,
3422 const char *user, const char *domain,
3423 const char *password, int flags,
3424 int signing_state)
3426 struct tevent_context *ev;
3427 struct tevent_req *req;
3428 NTSTATUS status = NT_STATUS_NO_MEMORY;
3430 ev = samba_tevent_context_init(talloc_tos());
3431 if (ev == NULL) {
3432 goto fail;
3434 req = cli_full_connection_send(
3435 ev, ev, my_name, dest_host, dest_ss, port, service,
3436 service_type, user, domain, password, flags, signing_state);
3437 if (req == NULL) {
3438 goto fail;
3440 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3441 goto fail;
3443 status = cli_full_connection_recv(req, output_cli);
3444 fail:
3445 TALLOC_FREE(ev);
3446 return status;
3449 /****************************************************************************
3450 Send an old style tcon.
3451 ****************************************************************************/
3452 struct cli_raw_tcon_state {
3453 uint16_t *ret_vwv;
3456 static void cli_raw_tcon_done(struct tevent_req *subreq);
3458 static struct tevent_req *cli_raw_tcon_send(
3459 TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
3460 const char *service, const char *pass, const char *dev)
3462 struct tevent_req *req, *subreq;
3463 struct cli_raw_tcon_state *state;
3464 uint8_t *bytes;
3466 req = tevent_req_create(mem_ctx, &state, struct cli_raw_tcon_state);
3467 if (req == NULL) {
3468 return NULL;
3471 if (!lp_client_plaintext_auth() && (*pass)) {
3472 DEBUG(1, ("Server requested PLAINTEXT password but 'client plaintext auth = no'"
3473 " or 'client ntlmv2 auth = yes'\n"));
3474 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
3475 return tevent_req_post(req, ev);
3478 bytes = talloc_array(state, uint8_t, 0);
3479 bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
3480 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
3481 service, strlen(service)+1, NULL);
3482 bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
3483 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
3484 pass, strlen(pass)+1, NULL);
3485 bytes = smb_bytes_push_bytes(bytes, 4, NULL, 0);
3486 bytes = smb_bytes_push_str(bytes, smbXcli_conn_use_unicode(cli->conn),
3487 dev, strlen(dev)+1, NULL);
3489 if (tevent_req_nomem(bytes, req)) {
3490 return tevent_req_post(req, ev);
3493 subreq = cli_smb_send(state, ev, cli, SMBtcon, 0, 0, NULL,
3494 talloc_get_size(bytes), bytes);
3495 if (tevent_req_nomem(subreq, req)) {
3496 return tevent_req_post(req, ev);
3498 tevent_req_set_callback(subreq, cli_raw_tcon_done, req);
3499 return req;
3502 static void cli_raw_tcon_done(struct tevent_req *subreq)
3504 struct tevent_req *req = tevent_req_callback_data(
3505 subreq, struct tevent_req);
3506 struct cli_raw_tcon_state *state = tevent_req_data(
3507 req, struct cli_raw_tcon_state);
3508 NTSTATUS status;
3510 status = cli_smb_recv(subreq, state, NULL, 2, NULL, &state->ret_vwv,
3511 NULL, NULL);
3512 TALLOC_FREE(subreq);
3513 if (tevent_req_nterror(req, status)) {
3514 return;
3516 tevent_req_done(req);
3519 static NTSTATUS cli_raw_tcon_recv(struct tevent_req *req,
3520 uint16 *max_xmit, uint16 *tid)
3522 struct cli_raw_tcon_state *state = tevent_req_data(
3523 req, struct cli_raw_tcon_state);
3524 NTSTATUS status;
3526 if (tevent_req_is_nterror(req, &status)) {
3527 return status;
3529 *max_xmit = SVAL(state->ret_vwv + 0, 0);
3530 *tid = SVAL(state->ret_vwv + 1, 0);
3531 return NT_STATUS_OK;
3534 NTSTATUS cli_raw_tcon(struct cli_state *cli,
3535 const char *service, const char *pass, const char *dev,
3536 uint16 *max_xmit, uint16 *tid)
3538 struct tevent_context *ev;
3539 struct tevent_req *req;
3540 NTSTATUS status = NT_STATUS_NO_MEMORY;
3542 ev = samba_tevent_context_init(talloc_tos());
3543 if (ev == NULL) {
3544 goto fail;
3546 req = cli_raw_tcon_send(ev, ev, cli, service, pass, dev);
3547 if (req == NULL) {
3548 goto fail;
3550 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3551 goto fail;
3553 status = cli_raw_tcon_recv(req, max_xmit, tid);
3554 fail:
3555 TALLOC_FREE(ev);
3556 return status;
3559 /* Return a cli_state pointing at the IPC$ share for the given server */
3561 struct cli_state *get_ipc_connect(char *server,
3562 struct sockaddr_storage *server_ss,
3563 const struct user_auth_info *user_info)
3565 struct cli_state *cli;
3566 NTSTATUS nt_status;
3567 uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
3569 if (user_info->use_kerberos) {
3570 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
3573 nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC",
3574 user_info->username ? user_info->username : "",
3575 lp_workgroup(),
3576 user_info->password ? user_info->password : "",
3577 flags,
3578 SMB_SIGNING_DEFAULT);
3580 if (NT_STATUS_IS_OK(nt_status)) {
3581 return cli;
3582 } else if (is_ipaddress(server)) {
3583 /* windows 9* needs a correct NMB name for connections */
3584 fstring remote_name;
3586 if (name_status_find("*", 0, 0, server_ss, remote_name)) {
3587 cli = get_ipc_connect(remote_name, server_ss, user_info);
3588 if (cli)
3589 return cli;
3592 return NULL;
3596 * Given the IP address of a master browser on the network, return its
3597 * workgroup and connect to it.
3599 * This function is provided to allow additional processing beyond what
3600 * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
3601 * browsers and obtain each master browsers' list of domains (in case the
3602 * first master browser is recently on the network and has not yet
3603 * synchronized with other master browsers and therefore does not yet have the
3604 * entire network browse list)
3607 struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
3608 struct sockaddr_storage *mb_ip,
3609 const struct user_auth_info *user_info,
3610 char **pp_workgroup_out)
3612 char addr[INET6_ADDRSTRLEN];
3613 fstring name;
3614 struct cli_state *cli;
3615 struct sockaddr_storage server_ss;
3617 *pp_workgroup_out = NULL;
3619 print_sockaddr(addr, sizeof(addr), mb_ip);
3620 DEBUG(99, ("Looking up name of master browser %s\n",
3621 addr));
3624 * Do a name status query to find out the name of the master browser.
3625 * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
3626 * master browser will not respond to a wildcard query (or, at least,
3627 * an NT4 server acting as the domain master browser will not).
3629 * We might be able to use ONLY the query on MSBROWSE, but that's not
3630 * yet been tested with all Windows versions, so until it is, leave
3631 * the original wildcard query as the first choice and fall back to
3632 * MSBROWSE if the wildcard query fails.
3634 if (!name_status_find("*", 0, 0x1d, mb_ip, name) &&
3635 !name_status_find(MSBROWSE, 1, 0x1d, mb_ip, name)) {
3637 DEBUG(99, ("Could not retrieve name status for %s\n",
3638 addr));
3639 return NULL;
3642 if (!find_master_ip(name, &server_ss)) {
3643 DEBUG(99, ("Could not find master ip for %s\n", name));
3644 return NULL;
3647 *pp_workgroup_out = talloc_strdup(ctx, name);
3649 DEBUG(4, ("found master browser %s, %s\n", name, addr));
3651 print_sockaddr(addr, sizeof(addr), &server_ss);
3652 cli = get_ipc_connect(addr, &server_ss, user_info);
3654 return cli;
3658 * Return the IP address and workgroup of a master browser on the network, and
3659 * connect to it.
3662 struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
3663 const struct user_auth_info *user_info,
3664 char **pp_workgroup_out)
3666 struct sockaddr_storage *ip_list;
3667 struct cli_state *cli;
3668 int i, count;
3669 NTSTATUS status;
3671 *pp_workgroup_out = NULL;
3673 DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
3675 /* Go looking for workgroups by broadcasting on the local network */
3677 status = name_resolve_bcast(MSBROWSE, 1, talloc_tos(),
3678 &ip_list, &count);
3679 if (!NT_STATUS_IS_OK(status)) {
3680 DEBUG(99, ("No master browsers responded: %s\n",
3681 nt_errstr(status)));
3682 return NULL;
3685 for (i = 0; i < count; i++) {
3686 char addr[INET6_ADDRSTRLEN];
3687 print_sockaddr(addr, sizeof(addr), &ip_list[i]);
3688 DEBUG(99, ("Found master browser %s\n", addr));
3690 cli = get_ipc_connect_master_ip(ctx, &ip_list[i],
3691 user_info, pp_workgroup_out);
3692 if (cli)
3693 return(cli);
3696 return NULL;