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
8 Copyright (C) Stefan Metzmacher 2016
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "system/network.h"
26 #include "../lib/util/tevent_ntstatus.h"
27 #include "../libcli/smb/smb_common.h"
28 #include "../libcli/smb/smbXcli_base.h"
31 struct smb1cli_session_setup_lm21_state
{
32 struct smbXcli_session
*session
;
34 struct iovec
*recv_iov
;
35 uint16_t out_session_id
;
41 static void smb1cli_session_setup_lm21_done(struct tevent_req
*subreq
);
43 struct tevent_req
*smb1cli_session_setup_lm21_send(TALLOC_CTX
*mem_ctx
,
44 struct tevent_context
*ev
,
45 struct smbXcli_conn
*conn
,
46 uint32_t timeout_msec
,
48 struct smbXcli_session
*session
,
54 const char *in_domain
,
55 const DATA_BLOB in_apassword
,
56 const char *in_native_os
,
57 const char *in_native_lm
)
59 struct tevent_req
*req
= NULL
;
60 struct smb1cli_session_setup_lm21_state
*state
= NULL
;
61 struct tevent_req
*subreq
= NULL
;
63 uint8_t *bytes
= NULL
;
65 req
= tevent_req_create(mem_ctx
, &state
,
66 struct smb1cli_session_setup_lm21_state
);
70 state
->session
= session
;
73 if (in_user
== NULL
) {
74 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
75 return tevent_req_post(req
, ev
);
78 if (in_domain
== NULL
) {
79 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
80 return tevent_req_post(req
, ev
);
83 if (in_apassword
.length
> UINT16_MAX
) {
84 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
85 return tevent_req_post(req
, ev
);
88 if (in_native_os
== NULL
&& in_native_lm
!= NULL
) {
89 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
90 return tevent_req_post(req
, ev
);
93 SCVAL(vwv
+0, 0, 0xff);
96 SSVAL(vwv
+2, 0, in_buf_size
);
97 SSVAL(vwv
+3, 0, in_mpx_max
);
98 SSVAL(vwv
+4, 0, in_vc_num
);
99 SIVAL(vwv
+5, 0, in_sess_key
);
100 SSVAL(vwv
+7, 0, in_apassword
.length
);
101 SSVAL(vwv
+8, 0, 0); /* reserved */
102 SSVAL(vwv
+9, 0, 0); /* reserved */
104 bytes
= talloc_array(state
, uint8_t,
105 in_apassword
.length
);
106 if (tevent_req_nomem(bytes
, req
)) {
107 return tevent_req_post(req
, ev
);
109 if (in_apassword
.length
!= 0) {
112 in_apassword
.length
);
115 bytes
= smb_bytes_push_str(bytes
,
116 smbXcli_conn_use_unicode(conn
),
117 in_user
, strlen(in_user
)+1,
119 bytes
= smb_bytes_push_str(bytes
,
120 smbXcli_conn_use_unicode(conn
),
121 in_domain
, strlen(in_domain
)+1,
123 if (in_native_os
!= NULL
) {
124 bytes
= smb_bytes_push_str(bytes
,
125 smbXcli_conn_use_unicode(conn
),
126 in_native_os
, strlen(in_native_os
)+1,
129 if (in_native_lm
!= NULL
) {
130 bytes
= smb_bytes_push_str(bytes
,
131 smbXcli_conn_use_unicode(conn
),
132 in_native_lm
, strlen(in_native_lm
)+1,
135 if (tevent_req_nomem(bytes
, req
)) {
136 return tevent_req_post(req
, ev
);
139 subreq
= smb1cli_req_send(state
, ev
, conn
,
141 0, /* additional_flags */
143 0, /* additional_flags2 */
144 0, /* clear_flags2 */
151 talloc_get_size(bytes
),
153 if (tevent_req_nomem(subreq
, req
)) {
154 return tevent_req_post(req
, ev
);
156 tevent_req_set_callback(subreq
, smb1cli_session_setup_lm21_done
, req
);
161 static void smb1cli_session_setup_lm21_done(struct tevent_req
*subreq
)
163 struct tevent_req
*req
=
164 tevent_req_callback_data(subreq
,
166 struct smb1cli_session_setup_lm21_state
*state
=
168 struct smb1cli_session_setup_lm21_state
);
170 uint8_t *inhdr
= NULL
;
172 uint16_t *vwv
= NULL
;
174 uint8_t *bytes
= NULL
;
175 const uint8_t *p
= NULL
;
178 bool use_unicode
= false;
179 struct smb1cli_req_expected_response expected
[] = {
181 .status
= NT_STATUS_OK
,
186 status
= smb1cli_req_recv(subreq
, state
,
191 NULL
, /* pvwv_offset */
194 NULL
, /* pbytes_offset */
196 expected
, ARRAY_SIZE(expected
));
198 if (tevent_req_nterror(req
, status
)) {
202 flags2
= SVAL(inhdr
, HDR_FLG2
);
203 if (flags2
& FLAGS2_UNICODE_STRINGS
) {
207 state
->out_session_id
= SVAL(inhdr
, HDR_UID
);
208 state
->out_action
= SVAL(vwv
+2, 0);
212 status
= smb_bytes_pull_str(state
, &state
->out_native_os
,
213 use_unicode
, bytes
, num_bytes
,
215 if (tevent_req_nterror(req
, status
)) {
220 status
= smb_bytes_pull_str(state
, &state
->out_native_lm
,
221 use_unicode
, bytes
, num_bytes
,
223 if (tevent_req_nterror(req
, status
)) {
228 smb1cli_session_set_id(state
->session
, state
->out_session_id
);
229 smb1cli_session_set_action(state
->session
, state
->out_action
);
231 tevent_req_done(req
);
234 NTSTATUS
smb1cli_session_setup_lm21_recv(struct tevent_req
*req
,
236 char **out_native_os
,
237 char **out_native_lm
)
239 struct smb1cli_session_setup_lm21_state
*state
=
241 struct smb1cli_session_setup_lm21_state
);
244 if (tevent_req_is_nterror(req
, &status
)) {
245 tevent_req_received(req
);
249 if (out_native_os
!= NULL
) {
250 *out_native_os
= talloc_move(mem_ctx
, &state
->out_native_os
);
253 if (out_native_lm
!= NULL
) {
254 *out_native_lm
= talloc_move(mem_ctx
, &state
->out_native_lm
);
257 tevent_req_received(req
);
261 struct smb1cli_session_setup_nt1_state
{
262 struct smbXcli_session
*session
;
264 struct iovec
*recv_iov
;
266 uint16_t out_session_id
;
270 char *out_primary_domain
;
273 static void smb1cli_session_setup_nt1_done(struct tevent_req
*subreq
);
275 struct tevent_req
*smb1cli_session_setup_nt1_send(TALLOC_CTX
*mem_ctx
,
276 struct tevent_context
*ev
,
277 struct smbXcli_conn
*conn
,
278 uint32_t timeout_msec
,
280 struct smbXcli_session
*session
,
281 uint16_t in_buf_size
,
284 uint32_t in_sess_key
,
286 const char *in_domain
,
287 const DATA_BLOB in_apassword
,
288 const DATA_BLOB in_upassword
,
289 uint32_t in_capabilities
,
290 const char *in_native_os
,
291 const char *in_native_lm
)
293 struct tevent_req
*req
= NULL
;
294 struct smb1cli_session_setup_nt1_state
*state
= NULL
;
295 struct tevent_req
*subreq
= NULL
;
296 uint16_t *vwv
= NULL
;
297 uint8_t *bytes
= NULL
;
298 size_t align_upassword
= 0;
299 size_t apassword_ofs
= 0;
300 size_t upassword_ofs
= 0;
302 req
= tevent_req_create(mem_ctx
, &state
,
303 struct smb1cli_session_setup_nt1_state
);
307 state
->session
= session
;
310 if (in_user
== NULL
) {
311 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
312 return tevent_req_post(req
, ev
);
315 if (in_domain
== NULL
) {
316 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
317 return tevent_req_post(req
, ev
);
320 if (in_apassword
.length
> UINT16_MAX
) {
321 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
322 return tevent_req_post(req
, ev
);
325 if (in_upassword
.length
> UINT16_MAX
) {
326 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
327 return tevent_req_post(req
, ev
);
330 if (in_native_os
== NULL
&& in_native_lm
!= NULL
) {
331 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
332 return tevent_req_post(req
, ev
);
335 SCVAL(vwv
+0, 0, 0xff);
338 SSVAL(vwv
+2, 0, in_buf_size
);
339 SSVAL(vwv
+3, 0, in_mpx_max
);
340 SSVAL(vwv
+4, 0, in_vc_num
);
341 SIVAL(vwv
+5, 0, in_sess_key
);
342 SSVAL(vwv
+7, 0, in_apassword
.length
);
343 SSVAL(vwv
+8, 0, in_upassword
.length
);
344 SSVAL(vwv
+9, 0, 0); /* reserved */
345 SSVAL(vwv
+10, 0, 0); /* reserved */
346 SIVAL(vwv
+11, 0, in_capabilities
);
348 if (in_apassword
.length
== 0 && in_upassword
.length
> 0) {
350 * This is plaintext auth with a unicode password,
351 * we need to align the buffer.
353 * This is what smbclient and Windows XP send as
354 * a client. And what smbd expects.
356 * But it doesn't follow [MS-CIFS] (v20160714)
357 * 2.2.4.53.1 SMB_COM_SESSION_SETUP_ANDX Request:
361 * If SMB_FLAGS2_UNICODE is set (1), the value of OEMPasswordLen
362 * MUST be 0x0000 and the password MUST be encoded using
363 * UTF-16LE Unicode. Padding MUST NOT be added to
364 * align this plaintext Unicode string to a word boundary.
368 uint16_t security_mode
= smb1cli_conn_server_security_mode(conn
);
370 if (!(security_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
)) {
375 bytes
= talloc_array(state
, uint8_t,
376 in_apassword
.length
+
378 in_upassword
.length
);
379 if (tevent_req_nomem(bytes
, req
)) {
380 return tevent_req_post(req
, ev
);
382 if (in_apassword
.length
!= 0) {
383 memcpy(bytes
+ apassword_ofs
,
385 in_apassword
.length
);
386 upassword_ofs
+= in_apassword
.length
;
388 if (align_upassword
!= 0) {
389 memset(bytes
+ upassword_ofs
, 0, align_upassword
);
390 upassword_ofs
+= align_upassword
;
392 if (in_upassword
.length
!= 0) {
393 memcpy(bytes
+ upassword_ofs
,
395 in_upassword
.length
);
398 bytes
= smb_bytes_push_str(bytes
,
399 smbXcli_conn_use_unicode(conn
),
400 in_user
, strlen(in_user
)+1,
402 bytes
= smb_bytes_push_str(bytes
,
403 smbXcli_conn_use_unicode(conn
),
404 in_domain
, strlen(in_domain
)+1,
406 if (in_native_os
!= NULL
) {
407 bytes
= smb_bytes_push_str(bytes
,
408 smbXcli_conn_use_unicode(conn
),
409 in_native_os
, strlen(in_native_os
)+1,
412 if (in_native_lm
!= NULL
) {
413 bytes
= smb_bytes_push_str(bytes
,
414 smbXcli_conn_use_unicode(conn
),
415 in_native_lm
, strlen(in_native_lm
)+1,
418 if (tevent_req_nomem(bytes
, req
)) {
419 return tevent_req_post(req
, ev
);
422 subreq
= smb1cli_req_send(state
, ev
, conn
,
424 0, /* additional_flags */
426 0, /* additional_flags2 */
427 0, /* clear_flags2 */
434 talloc_get_size(bytes
),
436 if (tevent_req_nomem(subreq
, req
)) {
437 return tevent_req_post(req
, ev
);
439 tevent_req_set_callback(subreq
, smb1cli_session_setup_nt1_done
, req
);
444 static void smb1cli_session_setup_nt1_done(struct tevent_req
*subreq
)
446 struct tevent_req
*req
=
447 tevent_req_callback_data(subreq
,
449 struct smb1cli_session_setup_nt1_state
*state
=
451 struct smb1cli_session_setup_nt1_state
);
453 uint8_t *inhdr
= NULL
;
455 uint16_t *vwv
= NULL
;
457 uint8_t *bytes
= NULL
;
458 const uint8_t *p
= NULL
;
461 bool use_unicode
= false;
462 struct smb1cli_req_expected_response expected
[] = {
464 .status
= NT_STATUS_OK
,
469 status
= smb1cli_req_recv(subreq
, state
,
474 NULL
, /* pvwv_offset */
477 NULL
, /* pbytes_offset */
479 expected
, ARRAY_SIZE(expected
));
481 if (tevent_req_nterror(req
, status
)) {
485 flags2
= SVAL(inhdr
, HDR_FLG2
);
486 if (flags2
& FLAGS2_UNICODE_STRINGS
) {
490 state
->out_session_id
= SVAL(inhdr
, HDR_UID
);
491 state
->out_action
= SVAL(vwv
+2, 0);
495 status
= smb_bytes_pull_str(state
, &state
->out_native_os
,
496 use_unicode
, bytes
, num_bytes
,
498 if (tevent_req_nterror(req
, status
)) {
503 status
= smb_bytes_pull_str(state
, &state
->out_native_lm
,
504 use_unicode
, bytes
, num_bytes
,
506 if (tevent_req_nterror(req
, status
)) {
511 status
= smb_bytes_pull_str(state
, &state
->out_primary_domain
,
512 use_unicode
, bytes
, num_bytes
,
514 if (tevent_req_nterror(req
, status
)) {
519 smb1cli_session_set_id(state
->session
, state
->out_session_id
);
520 smb1cli_session_set_action(state
->session
, state
->out_action
);
522 tevent_req_done(req
);
525 NTSTATUS
smb1cli_session_setup_nt1_recv(struct tevent_req
*req
,
527 struct iovec
**precv_iov
,
528 const uint8_t **precv_inbuf
,
529 char **out_native_os
,
530 char **out_native_lm
,
531 char **out_primary_domain
)
533 struct smb1cli_session_setup_nt1_state
*state
=
535 struct smb1cli_session_setup_nt1_state
);
537 struct iovec
*recv_iov
= NULL
;
539 if (tevent_req_is_nterror(req
, &status
)) {
540 tevent_req_received(req
);
544 recv_iov
= talloc_move(mem_ctx
, &state
->recv_iov
);
545 if (precv_iov
!= NULL
) {
546 *precv_iov
= recv_iov
;
548 if (precv_inbuf
!= NULL
) {
549 *precv_inbuf
= state
->inbuf
;
552 if (out_native_os
!= NULL
) {
553 *out_native_os
= talloc_move(mem_ctx
, &state
->out_native_os
);
556 if (out_native_lm
!= NULL
) {
557 *out_native_lm
= talloc_move(mem_ctx
, &state
->out_native_lm
);
560 if (out_primary_domain
!= NULL
) {
561 *out_primary_domain
= talloc_move(mem_ctx
,
562 &state
->out_primary_domain
);
565 tevent_req_received(req
);
569 struct smb1cli_session_setup_ext_state
{
570 struct smbXcli_session
*session
;
572 struct iovec
*recv_iov
;
575 uint16_t out_session_id
;
577 DATA_BLOB out_security_blob
;
582 static void smb1cli_session_setup_ext_done(struct tevent_req
*subreq
);
584 struct tevent_req
*smb1cli_session_setup_ext_send(TALLOC_CTX
*mem_ctx
,
585 struct tevent_context
*ev
,
586 struct smbXcli_conn
*conn
,
587 uint32_t timeout_msec
,
589 struct smbXcli_session
*session
,
590 uint16_t in_buf_size
,
593 uint32_t in_sess_key
,
594 const DATA_BLOB in_security_blob
,
595 uint32_t in_capabilities
,
596 const char *in_native_os
,
597 const char *in_native_lm
)
599 struct tevent_req
*req
= NULL
;
600 struct smb1cli_session_setup_ext_state
*state
= NULL
;
601 struct tevent_req
*subreq
= NULL
;
602 uint16_t *vwv
= NULL
;
603 uint8_t *bytes
= NULL
;
605 req
= tevent_req_create(mem_ctx
, &state
,
606 struct smb1cli_session_setup_ext_state
);
610 state
->session
= session
;
613 if (in_security_blob
.length
> UINT16_MAX
) {
614 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
615 return tevent_req_post(req
, ev
);
618 if (in_native_os
== NULL
&& in_native_lm
!= NULL
) {
619 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
620 return tevent_req_post(req
, ev
);
623 SCVAL(vwv
+0, 0, 0xff);
626 SSVAL(vwv
+2, 0, in_buf_size
);
627 SSVAL(vwv
+3, 0, in_mpx_max
);
628 SSVAL(vwv
+4, 0, in_vc_num
);
629 SIVAL(vwv
+5, 0, in_sess_key
);
630 SSVAL(vwv
+7, 0, in_security_blob
.length
);
631 SSVAL(vwv
+8, 0, 0); /* reserved */
632 SSVAL(vwv
+9, 0, 0); /* reserved */
633 SIVAL(vwv
+10, 0, in_capabilities
);
635 bytes
= talloc_array(state
, uint8_t,
636 in_security_blob
.length
);
637 if (tevent_req_nomem(bytes
, req
)) {
638 return tevent_req_post(req
, ev
);
640 if (in_security_blob
.length
!= 0) {
642 in_security_blob
.data
,
643 in_security_blob
.length
);
646 if (in_native_os
!= NULL
) {
647 bytes
= smb_bytes_push_str(bytes
,
648 smbXcli_conn_use_unicode(conn
),
649 in_native_os
, strlen(in_native_os
)+1,
652 if (in_native_lm
!= NULL
) {
653 bytes
= smb_bytes_push_str(bytes
,
654 smbXcli_conn_use_unicode(conn
),
655 in_native_lm
, strlen(in_native_lm
)+1,
658 if (tevent_req_nomem(bytes
, req
)) {
659 return tevent_req_post(req
, ev
);
662 subreq
= smb1cli_req_send(state
, ev
, conn
,
664 0, /* additional_flags */
666 0, /* additional_flags2 */
667 0, /* clear_flags2 */
674 talloc_get_size(bytes
),
676 if (tevent_req_nomem(subreq
, req
)) {
677 return tevent_req_post(req
, ev
);
679 tevent_req_set_callback(subreq
, smb1cli_session_setup_ext_done
, req
);
684 static void smb1cli_session_setup_ext_done(struct tevent_req
*subreq
)
686 struct tevent_req
*req
=
687 tevent_req_callback_data(subreq
,
689 struct smb1cli_session_setup_ext_state
*state
=
691 struct smb1cli_session_setup_ext_state
);
693 uint8_t *inhdr
= NULL
;
695 uint16_t *vwv
= NULL
;
697 uint8_t *bytes
= NULL
;
698 const uint8_t *p
= NULL
;
701 uint16_t out_security_blob_length
= 0;
702 bool use_unicode
= false;
703 struct smb1cli_req_expected_response expected
[] = {
705 .status
= NT_STATUS_OK
,
709 .status
= NT_STATUS_MORE_PROCESSING_REQUIRED
,
714 status
= smb1cli_req_recv(subreq
, state
,
719 NULL
, /* pvwv_offset */
722 NULL
, /* pbytes_offset */
724 expected
, ARRAY_SIZE(expected
));
726 state
->status
= status
;
727 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
728 status
= NT_STATUS_OK
;
730 if (tevent_req_nterror(req
, status
)) {
734 flags2
= SVAL(inhdr
, HDR_FLG2
);
735 if (flags2
& FLAGS2_UNICODE_STRINGS
) {
739 state
->out_session_id
= SVAL(inhdr
, HDR_UID
);
740 state
->out_action
= SVAL(vwv
+2, 0);
741 out_security_blob_length
= SVAL(vwv
+3, 0);
743 if (out_security_blob_length
> num_bytes
) {
744 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
751 * Note: this points into state->recv_iov!
753 state
->out_security_blob
= data_blob_const(p
, out_security_blob_length
);
754 p
+= out_security_blob_length
;
756 status
= smb_bytes_pull_str(state
, &state
->out_native_os
,
757 use_unicode
, bytes
, num_bytes
,
759 if (tevent_req_nterror(req
, status
)) {
764 status
= smb_bytes_pull_str(state
, &state
->out_native_lm
,
765 use_unicode
, bytes
, num_bytes
,
767 if (tevent_req_nterror(req
, status
)) {
772 smb1cli_session_set_id(state
->session
, state
->out_session_id
);
773 smb1cli_session_set_action(state
->session
, state
->out_action
);
775 tevent_req_done(req
);
778 NTSTATUS
smb1cli_session_setup_ext_recv(struct tevent_req
*req
,
780 struct iovec
**precv_iov
,
781 const uint8_t **precv_inbuf
,
782 DATA_BLOB
*out_security_blob
,
783 char **out_native_os
,
784 char **out_native_lm
)
786 struct smb1cli_session_setup_ext_state
*state
=
788 struct smb1cli_session_setup_ext_state
);
790 struct iovec
*recv_iov
= NULL
;
792 if (tevent_req_is_nterror(req
, &status
)) {
793 tevent_req_received(req
);
797 recv_iov
= talloc_move(mem_ctx
, &state
->recv_iov
);
798 if (precv_iov
!= NULL
) {
799 *precv_iov
= recv_iov
;
801 if (precv_inbuf
!= NULL
) {
802 *precv_inbuf
= state
->inbuf
;
805 *out_security_blob
= state
->out_security_blob
;
807 if (out_native_os
!= NULL
) {
808 *out_native_os
= talloc_move(mem_ctx
, &state
->out_native_os
);
811 if (out_native_lm
!= NULL
) {
812 *out_native_lm
= talloc_move(mem_ctx
, &state
->out_native_lm
);
816 * Return the status from the server:
817 * NT_STATUS_MORE_PROCESSING_REQUIRED or
820 status
= state
->status
;
821 tevent_req_received(req
);