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
)) {
227 smb1cli_session_set_id(state
->session
, state
->out_session_id
);
228 smb1cli_session_set_action(state
->session
, state
->out_action
);
230 tevent_req_done(req
);
233 NTSTATUS
smb1cli_session_setup_lm21_recv(struct tevent_req
*req
,
235 char **out_native_os
,
236 char **out_native_lm
)
238 struct smb1cli_session_setup_lm21_state
*state
=
240 struct smb1cli_session_setup_lm21_state
);
243 if (tevent_req_is_nterror(req
, &status
)) {
244 tevent_req_received(req
);
248 if (out_native_os
!= NULL
) {
249 *out_native_os
= talloc_move(mem_ctx
, &state
->out_native_os
);
252 if (out_native_lm
!= NULL
) {
253 *out_native_lm
= talloc_move(mem_ctx
, &state
->out_native_lm
);
256 tevent_req_received(req
);
260 struct smb1cli_session_setup_nt1_state
{
261 struct smbXcli_session
*session
;
263 struct iovec
*recv_iov
;
265 uint16_t out_session_id
;
269 char *out_primary_domain
;
272 static void smb1cli_session_setup_nt1_done(struct tevent_req
*subreq
);
274 struct tevent_req
*smb1cli_session_setup_nt1_send(TALLOC_CTX
*mem_ctx
,
275 struct tevent_context
*ev
,
276 struct smbXcli_conn
*conn
,
277 uint32_t timeout_msec
,
279 struct smbXcli_session
*session
,
280 uint16_t in_buf_size
,
283 uint32_t in_sess_key
,
285 const char *in_domain
,
286 const DATA_BLOB in_apassword
,
287 const DATA_BLOB in_upassword
,
288 uint32_t in_capabilities
,
289 const char *in_native_os
,
290 const char *in_native_lm
)
292 struct tevent_req
*req
= NULL
;
293 struct smb1cli_session_setup_nt1_state
*state
= NULL
;
294 struct tevent_req
*subreq
= NULL
;
295 uint16_t *vwv
= NULL
;
296 uint8_t *bytes
= NULL
;
297 size_t align_upassword
= 0;
298 size_t apassword_ofs
= 0;
299 size_t upassword_ofs
= 0;
301 req
= tevent_req_create(mem_ctx
, &state
,
302 struct smb1cli_session_setup_nt1_state
);
306 state
->session
= session
;
309 if (in_user
== NULL
) {
310 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
311 return tevent_req_post(req
, ev
);
314 if (in_domain
== NULL
) {
315 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
316 return tevent_req_post(req
, ev
);
319 if (in_apassword
.length
> UINT16_MAX
) {
320 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
321 return tevent_req_post(req
, ev
);
324 if (in_upassword
.length
> UINT16_MAX
) {
325 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
326 return tevent_req_post(req
, ev
);
329 if (in_native_os
== NULL
&& in_native_lm
!= NULL
) {
330 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
331 return tevent_req_post(req
, ev
);
334 SCVAL(vwv
+0, 0, 0xff);
337 SSVAL(vwv
+2, 0, in_buf_size
);
338 SSVAL(vwv
+3, 0, in_mpx_max
);
339 SSVAL(vwv
+4, 0, in_vc_num
);
340 SIVAL(vwv
+5, 0, in_sess_key
);
341 SSVAL(vwv
+7, 0, in_apassword
.length
);
342 SSVAL(vwv
+8, 0, in_upassword
.length
);
343 SSVAL(vwv
+9, 0, 0); /* reserved */
344 SSVAL(vwv
+10, 0, 0); /* reserved */
345 SIVAL(vwv
+11, 0, in_capabilities
);
347 if (in_apassword
.length
== 0 && in_upassword
.length
> 0) {
349 * This is plaintext auth with a unicode password,
350 * we need to align the buffer.
352 * This is what smbclient and Windows XP send as
353 * a client. And what smbd expects.
355 * But it doesn't follow [MS-CIFS] (v20160714)
356 * 2.2.4.53.1 SMB_COM_SESSION_SETUP_ANDX Request:
360 * If SMB_FLAGS2_UNICODE is set (1), the value of OEMPasswordLen
361 * MUST be 0x0000 and the password MUST be encoded using
362 * UTF-16LE Unicode. Padding MUST NOT be added to
363 * align this plaintext Unicode string to a word boundary.
367 uint16_t security_mode
= smb1cli_conn_server_security_mode(conn
);
369 if (!(security_mode
& NEGOTIATE_SECURITY_CHALLENGE_RESPONSE
)) {
374 bytes
= talloc_array(state
, uint8_t,
375 in_apassword
.length
+
377 in_upassword
.length
);
378 if (tevent_req_nomem(bytes
, req
)) {
379 return tevent_req_post(req
, ev
);
381 if (in_apassword
.length
!= 0) {
382 memcpy(bytes
+ apassword_ofs
,
384 in_apassword
.length
);
385 upassword_ofs
+= in_apassword
.length
;
387 if (align_upassword
!= 0) {
388 memset(bytes
+ upassword_ofs
, 0, align_upassword
);
389 upassword_ofs
+= align_upassword
;
391 if (in_upassword
.length
!= 0) {
392 memcpy(bytes
+ upassword_ofs
,
394 in_upassword
.length
);
397 bytes
= smb_bytes_push_str(bytes
,
398 smbXcli_conn_use_unicode(conn
),
399 in_user
, strlen(in_user
)+1,
401 bytes
= smb_bytes_push_str(bytes
,
402 smbXcli_conn_use_unicode(conn
),
403 in_domain
, strlen(in_domain
)+1,
405 if (in_native_os
!= NULL
) {
406 bytes
= smb_bytes_push_str(bytes
,
407 smbXcli_conn_use_unicode(conn
),
408 in_native_os
, strlen(in_native_os
)+1,
411 if (in_native_lm
!= NULL
) {
412 bytes
= smb_bytes_push_str(bytes
,
413 smbXcli_conn_use_unicode(conn
),
414 in_native_lm
, strlen(in_native_lm
)+1,
417 if (tevent_req_nomem(bytes
, req
)) {
418 return tevent_req_post(req
, ev
);
421 subreq
= smb1cli_req_send(state
, ev
, conn
,
423 0, /* additional_flags */
425 0, /* additional_flags2 */
426 0, /* clear_flags2 */
433 talloc_get_size(bytes
),
435 if (tevent_req_nomem(subreq
, req
)) {
436 return tevent_req_post(req
, ev
);
438 tevent_req_set_callback(subreq
, smb1cli_session_setup_nt1_done
, req
);
443 static void smb1cli_session_setup_nt1_done(struct tevent_req
*subreq
)
445 struct tevent_req
*req
=
446 tevent_req_callback_data(subreq
,
448 struct smb1cli_session_setup_nt1_state
*state
=
450 struct smb1cli_session_setup_nt1_state
);
452 uint8_t *inhdr
= NULL
;
454 uint16_t *vwv
= NULL
;
456 uint8_t *bytes
= NULL
;
457 const uint8_t *p
= NULL
;
460 bool use_unicode
= false;
461 struct smb1cli_req_expected_response expected
[] = {
463 .status
= NT_STATUS_OK
,
468 status
= smb1cli_req_recv(subreq
, state
,
473 NULL
, /* pvwv_offset */
476 NULL
, /* pbytes_offset */
478 expected
, ARRAY_SIZE(expected
));
480 if (tevent_req_nterror(req
, status
)) {
484 flags2
= SVAL(inhdr
, HDR_FLG2
);
485 if (flags2
& FLAGS2_UNICODE_STRINGS
) {
489 state
->out_session_id
= SVAL(inhdr
, HDR_UID
);
490 state
->out_action
= SVAL(vwv
+2, 0);
494 status
= smb_bytes_pull_str(state
, &state
->out_native_os
,
495 use_unicode
, bytes
, num_bytes
,
497 if (tevent_req_nterror(req
, status
)) {
502 status
= smb_bytes_pull_str(state
, &state
->out_native_lm
,
503 use_unicode
, bytes
, num_bytes
,
505 if (tevent_req_nterror(req
, status
)) {
510 status
= smb_bytes_pull_str(state
, &state
->out_primary_domain
,
511 use_unicode
, bytes
, num_bytes
,
513 if (tevent_req_nterror(req
, status
)) {
517 smb1cli_session_set_id(state
->session
, state
->out_session_id
);
518 smb1cli_session_set_action(state
->session
, state
->out_action
);
520 tevent_req_done(req
);
523 NTSTATUS
smb1cli_session_setup_nt1_recv(struct tevent_req
*req
,
525 struct iovec
**precv_iov
,
526 const uint8_t **precv_inbuf
,
527 char **out_native_os
,
528 char **out_native_lm
,
529 char **out_primary_domain
)
531 struct smb1cli_session_setup_nt1_state
*state
=
533 struct smb1cli_session_setup_nt1_state
);
535 struct iovec
*recv_iov
= NULL
;
537 if (tevent_req_is_nterror(req
, &status
)) {
538 tevent_req_received(req
);
542 recv_iov
= talloc_move(mem_ctx
, &state
->recv_iov
);
543 if (precv_iov
!= NULL
) {
544 *precv_iov
= recv_iov
;
546 if (precv_inbuf
!= NULL
) {
547 *precv_inbuf
= state
->inbuf
;
550 if (out_native_os
!= NULL
) {
551 *out_native_os
= talloc_move(mem_ctx
, &state
->out_native_os
);
554 if (out_native_lm
!= NULL
) {
555 *out_native_lm
= talloc_move(mem_ctx
, &state
->out_native_lm
);
558 if (out_primary_domain
!= NULL
) {
559 *out_primary_domain
= talloc_move(mem_ctx
,
560 &state
->out_primary_domain
);
563 tevent_req_received(req
);
567 struct smb1cli_session_setup_ext_state
{
568 struct smbXcli_session
*session
;
570 struct iovec
*recv_iov
;
573 uint16_t out_session_id
;
575 DATA_BLOB out_security_blob
;
580 static void smb1cli_session_setup_ext_done(struct tevent_req
*subreq
);
582 struct tevent_req
*smb1cli_session_setup_ext_send(TALLOC_CTX
*mem_ctx
,
583 struct tevent_context
*ev
,
584 struct smbXcli_conn
*conn
,
585 uint32_t timeout_msec
,
587 struct smbXcli_session
*session
,
588 uint16_t in_buf_size
,
591 uint32_t in_sess_key
,
592 const DATA_BLOB in_security_blob
,
593 uint32_t in_capabilities
,
594 const char *in_native_os
,
595 const char *in_native_lm
)
597 struct tevent_req
*req
= NULL
;
598 struct smb1cli_session_setup_ext_state
*state
= NULL
;
599 struct tevent_req
*subreq
= NULL
;
600 uint16_t *vwv
= NULL
;
601 uint8_t *bytes
= NULL
;
603 req
= tevent_req_create(mem_ctx
, &state
,
604 struct smb1cli_session_setup_ext_state
);
608 state
->session
= session
;
611 if (in_security_blob
.length
> UINT16_MAX
) {
612 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
613 return tevent_req_post(req
, ev
);
616 if (in_native_os
== NULL
&& in_native_lm
!= NULL
) {
617 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
618 return tevent_req_post(req
, ev
);
621 SCVAL(vwv
+0, 0, 0xff);
624 SSVAL(vwv
+2, 0, in_buf_size
);
625 SSVAL(vwv
+3, 0, in_mpx_max
);
626 SSVAL(vwv
+4, 0, in_vc_num
);
627 SIVAL(vwv
+5, 0, in_sess_key
);
628 SSVAL(vwv
+7, 0, in_security_blob
.length
);
629 SSVAL(vwv
+8, 0, 0); /* reserved */
630 SSVAL(vwv
+9, 0, 0); /* reserved */
631 SIVAL(vwv
+10, 0, in_capabilities
);
633 bytes
= talloc_array(state
, uint8_t,
634 in_security_blob
.length
);
635 if (tevent_req_nomem(bytes
, req
)) {
636 return tevent_req_post(req
, ev
);
638 if (in_security_blob
.length
!= 0) {
640 in_security_blob
.data
,
641 in_security_blob
.length
);
644 if (in_native_os
!= NULL
) {
645 bytes
= smb_bytes_push_str(bytes
,
646 smbXcli_conn_use_unicode(conn
),
647 in_native_os
, strlen(in_native_os
)+1,
650 if (in_native_lm
!= NULL
) {
651 bytes
= smb_bytes_push_str(bytes
,
652 smbXcli_conn_use_unicode(conn
),
653 in_native_lm
, strlen(in_native_lm
)+1,
656 if (tevent_req_nomem(bytes
, req
)) {
657 return tevent_req_post(req
, ev
);
660 subreq
= smb1cli_req_send(state
, ev
, conn
,
662 0, /* additional_flags */
664 0, /* additional_flags2 */
665 0, /* clear_flags2 */
672 talloc_get_size(bytes
),
674 if (tevent_req_nomem(subreq
, req
)) {
675 return tevent_req_post(req
, ev
);
677 tevent_req_set_callback(subreq
, smb1cli_session_setup_ext_done
, req
);
682 static void smb1cli_session_setup_ext_done(struct tevent_req
*subreq
)
684 struct tevent_req
*req
=
685 tevent_req_callback_data(subreq
,
687 struct smb1cli_session_setup_ext_state
*state
=
689 struct smb1cli_session_setup_ext_state
);
691 uint8_t *inhdr
= NULL
;
693 uint16_t *vwv
= NULL
;
695 uint8_t *bytes
= NULL
;
696 const uint8_t *p
= NULL
;
699 uint16_t out_security_blob_length
= 0;
700 bool use_unicode
= false;
701 struct smb1cli_req_expected_response expected
[] = {
703 .status
= NT_STATUS_OK
,
707 .status
= NT_STATUS_MORE_PROCESSING_REQUIRED
,
712 status
= smb1cli_req_recv(subreq
, state
,
717 NULL
, /* pvwv_offset */
720 NULL
, /* pbytes_offset */
722 expected
, ARRAY_SIZE(expected
));
724 state
->status
= status
;
725 if (NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
726 status
= NT_STATUS_OK
;
728 if (tevent_req_nterror(req
, status
)) {
732 flags2
= SVAL(inhdr
, HDR_FLG2
);
733 if (flags2
& FLAGS2_UNICODE_STRINGS
) {
737 state
->out_session_id
= SVAL(inhdr
, HDR_UID
);
738 state
->out_action
= SVAL(vwv
+2, 0);
739 out_security_blob_length
= SVAL(vwv
+3, 0);
741 if (out_security_blob_length
> num_bytes
) {
742 tevent_req_nterror(req
, NT_STATUS_INVALID_NETWORK_RESPONSE
);
749 * Note: this points into state->recv_iov!
751 state
->out_security_blob
= data_blob_const(p
, out_security_blob_length
);
752 p
+= out_security_blob_length
;
754 status
= smb_bytes_pull_str(state
, &state
->out_native_os
,
755 use_unicode
, bytes
, num_bytes
,
757 if (tevent_req_nterror(req
, status
)) {
762 status
= smb_bytes_pull_str(state
, &state
->out_native_lm
,
763 use_unicode
, bytes
, num_bytes
,
765 if (tevent_req_nterror(req
, status
)) {
770 smb1cli_session_set_id(state
->session
, state
->out_session_id
);
771 smb1cli_session_set_action(state
->session
, state
->out_action
);
773 tevent_req_done(req
);
776 NTSTATUS
smb1cli_session_setup_ext_recv(struct tevent_req
*req
,
778 struct iovec
**precv_iov
,
779 const uint8_t **precv_inbuf
,
780 DATA_BLOB
*out_security_blob
,
781 char **out_native_os
,
782 char **out_native_lm
)
784 struct smb1cli_session_setup_ext_state
*state
=
786 struct smb1cli_session_setup_ext_state
);
788 struct iovec
*recv_iov
= NULL
;
790 if (tevent_req_is_nterror(req
, &status
)) {
791 tevent_req_received(req
);
795 recv_iov
= talloc_move(mem_ctx
, &state
->recv_iov
);
796 if (precv_iov
!= NULL
) {
797 *precv_iov
= recv_iov
;
799 if (precv_inbuf
!= NULL
) {
800 *precv_inbuf
= state
->inbuf
;
803 *out_security_blob
= state
->out_security_blob
;
805 if (out_native_os
!= NULL
) {
806 *out_native_os
= talloc_move(mem_ctx
, &state
->out_native_os
);
809 if (out_native_lm
!= NULL
) {
810 *out_native_lm
= talloc_move(mem_ctx
, &state
->out_native_lm
);
814 * Return the status from the server:
815 * NT_STATUS_MORE_PROCESSING_REQUIRED or
818 status
= state
->status
;
819 tevent_req_received(req
);