diff options
author | Stefan Metzmacher <metze@samba.org> | 2016-10-25 15:40:59 +0200 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2016-11-15 11:00:26 +0100 |
commit | 35ed3eeb0670ce90c704ca3aac6f31f81b4750e8 (patch) | |
tree | f3380739eec69b09a056702bb2800d7e8d50fa8c /libcli | |
parent | 2182817c9705c16e39acae3cf4aff8b1c3d27913 (diff) | |
download | samba-35ed3eeb0670ce90c704ca3aac6f31f81b4750e8.tar.gz |
libcli/smb: add smb1cli_session_setup_nt1_send/recv()
This does a session setup for the NT1 protocol (without CAP_EXTENDED_SECURITY).
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Diffstat (limited to 'libcli')
-rw-r--r-- | libcli/smb/smb1cli_session.c | 308 | ||||
-rw-r--r-- | libcli/smb/smbXcli_base.h | 24 |
2 files changed, 332 insertions, 0 deletions
diff --git a/libcli/smb/smb1cli_session.c b/libcli/smb/smb1cli_session.c index 1f6779a6d31..c2ed267797a 100644 --- a/libcli/smb/smb1cli_session.c +++ b/libcli/smb/smb1cli_session.c @@ -257,3 +257,311 @@ NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req, tevent_req_received(req); return NT_STATUS_OK; } + +struct smb1cli_session_setup_nt1_state { + struct smbXcli_session *session; + uint16_t vwv[13]; + struct iovec *recv_iov; + uint8_t *inbuf; + uint16_t out_session_id; + uint16_t out_action; + char *out_native_os; + char *out_native_lm; + char *out_primary_domain; +}; + +static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq); + +struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbXcli_conn *conn, + uint32_t timeout_msec, + uint32_t pid, + struct smbXcli_session *session, + uint16_t in_buf_size, + uint16_t in_mpx_max, + uint16_t in_vc_num, + uint32_t in_sess_key, + const char *in_user, + const char *in_domain, + const DATA_BLOB in_apassword, + const DATA_BLOB in_upassword, + uint32_t in_capabilities, + const char *in_native_os, + const char *in_native_lm) +{ + struct tevent_req *req = NULL; + struct smb1cli_session_setup_nt1_state *state = NULL; + struct tevent_req *subreq = NULL; + uint16_t *vwv = NULL; + uint8_t *bytes = NULL; + size_t align_upassword = 0; + size_t apassword_ofs = 0; + size_t upassword_ofs = 0; + + req = tevent_req_create(mem_ctx, &state, + struct smb1cli_session_setup_nt1_state); + if (req == NULL) { + return NULL; + } + state->session = session; + vwv = state->vwv; + + if (in_user == NULL) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); + return tevent_req_post(req, ev); + } + + if (in_domain == NULL) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); + return tevent_req_post(req, ev); + } + + if (in_apassword.length > UINT16_MAX) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); + return tevent_req_post(req, ev); + } + + if (in_upassword.length > UINT16_MAX) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); + return tevent_req_post(req, ev); + } + + if (in_native_os == NULL && in_native_lm != NULL) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); + return tevent_req_post(req, ev); + } + + SCVAL(vwv+0, 0, 0xff); + SCVAL(vwv+0, 1, 0); + SSVAL(vwv+1, 0, 0); + SSVAL(vwv+2, 0, in_buf_size); + SSVAL(vwv+3, 0, in_mpx_max); + SSVAL(vwv+4, 0, in_vc_num); + SIVAL(vwv+5, 0, in_sess_key); + SSVAL(vwv+7, 0, in_apassword.length); + SSVAL(vwv+8, 0, in_upassword.length); + SSVAL(vwv+9, 0, 0); /* reserved */ + SSVAL(vwv+10, 0, 0); /* reserved */ + SIVAL(vwv+11, 0, in_capabilities); + + if (in_apassword.length == 0 && in_upassword.length > 0) { + /* + * This is plaintext auth with a unicode password, + * we need to align the buffer. + * + * This is what smbclient and Windows XP send as + * a client. And what smbd expects. + * + * But it doesn't follow [MS-CIFS] (v20160714) + * 2.2.4.53.1 SMB_COM_SESSION_SETUP_ANDX Request: + * + * ... + * + * If SMB_FLAGS2_UNICODE is set (1), the value of OEMPasswordLen + * MUST be 0x0000 and the password MUST be encoded using + * UTF-16LE Unicode. Padding MUST NOT be added to + * align this plaintext Unicode string to a word boundary. + * + * ... + */ + uint16_t security_mode = smb1cli_conn_server_security_mode(conn); + + if (!(security_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) { + align_upassword = 1; + } + } + + bytes = talloc_array(state, uint8_t, + in_apassword.length + + align_upassword + + in_upassword.length); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } + if (in_apassword.length != 0) { + memcpy(bytes + apassword_ofs, + in_apassword.data, + in_apassword.length); + upassword_ofs += in_apassword.length; + } + if (align_upassword != 0) { + memset(bytes + upassword_ofs, 0, align_upassword); + upassword_ofs += align_upassword; + } + if (in_upassword.length != 0) { + memcpy(bytes + upassword_ofs, + in_upassword.data, + in_upassword.length); + } + + bytes = smb_bytes_push_str(bytes, + smbXcli_conn_use_unicode(conn), + in_user, strlen(in_user)+1, + NULL); + bytes = smb_bytes_push_str(bytes, + smbXcli_conn_use_unicode(conn), + in_domain, strlen(in_domain)+1, + NULL); + if (in_native_os != NULL) { + bytes = smb_bytes_push_str(bytes, + smbXcli_conn_use_unicode(conn), + in_native_os, strlen(in_native_os)+1, + NULL); + } + if (in_native_lm != NULL) { + bytes = smb_bytes_push_str(bytes, + smbXcli_conn_use_unicode(conn), + in_native_lm, strlen(in_native_lm)+1, + NULL); + } + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } + + subreq = smb1cli_req_send(state, ev, conn, + SMBsesssetupX, + 0, /* additional_flags */ + 0, /* clear_flags */ + 0, /* additional_flags2 */ + 0, /* clear_flags2 */ + timeout_msec, + pid, + NULL, /* tcon */ + session, + 13, /* wct */ + vwv, + talloc_get_size(bytes), + bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, smb1cli_session_setup_nt1_done, req); + + return req; +} + +static void smb1cli_session_setup_nt1_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct smb1cli_session_setup_nt1_state *state = + tevent_req_data(req, + struct smb1cli_session_setup_nt1_state); + NTSTATUS status; + uint8_t *inhdr = NULL; + uint8_t wct; + uint16_t *vwv = NULL; + uint32_t num_bytes; + uint8_t *bytes = NULL; + const uint8_t *p = NULL; + size_t ret = 0; + uint16_t flags2; + bool use_unicode = false; + struct smb1cli_req_expected_response expected[] = { + { + .status = NT_STATUS_OK, + .wct = 3, + }, + }; + + status = smb1cli_req_recv(subreq, state, + &state->recv_iov, + &inhdr, + &wct, + &vwv, + NULL, /* pvwv_offset */ + &num_bytes, + &bytes, + NULL, /* pbytes_offset */ + &state->inbuf, + expected, ARRAY_SIZE(expected)); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + flags2 = SVAL(inhdr, HDR_FLG2); + if (flags2 & FLAGS2_UNICODE_STRINGS) { + use_unicode = true; + } + + state->out_session_id = SVAL(inhdr, HDR_UID); + state->out_action = SVAL(vwv+2, 0); + + p = bytes; + + status = smb_bytes_pull_str(state, &state->out_native_os, + use_unicode, p, + bytes+num_bytes-p, &ret); + if (tevent_req_nterror(req, status)) { + return; + } + p += ret; + + status = smb_bytes_pull_str(state, &state->out_native_lm, + use_unicode, p, + bytes+num_bytes-p, &ret); + if (tevent_req_nterror(req, status)) { + return; + } + p += ret; + + status = smb_bytes_pull_str(state, &state->out_primary_domain, + use_unicode, p, + bytes+num_bytes-p, &ret); + if (tevent_req_nterror(req, status)) { + return; + } + p += ret; + + smb1cli_session_set_id(state->session, state->out_session_id); + smb1cli_session_set_action(state->session, state->out_action); + + tevent_req_done(req); +} + +NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct iovec **precv_iov, + const uint8_t **precv_inbuf, + char **out_native_os, + char **out_native_lm, + char **out_primary_domain) +{ + struct smb1cli_session_setup_nt1_state *state = + tevent_req_data(req, + struct smb1cli_session_setup_nt1_state); + NTSTATUS status; + struct iovec *recv_iov = NULL; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + recv_iov = talloc_move(mem_ctx, &state->recv_iov); + if (precv_iov != NULL) { + *precv_iov = recv_iov; + } + if (precv_inbuf != NULL) { + *precv_inbuf = state->inbuf; + } + + if (out_native_os != NULL) { + *out_native_os = talloc_move(mem_ctx, &state->out_native_os); + } + + if (out_native_lm != NULL) { + *out_native_lm = talloc_move(mem_ctx, &state->out_native_lm); + } + + if (out_primary_domain != NULL) { + *out_primary_domain = talloc_move(mem_ctx, + &state->out_primary_domain); + } + + tevent_req_received(req); + return NT_STATUS_OK; +} diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index c1a9c701611..ad4272171ed 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -220,6 +220,30 @@ NTSTATUS smb1cli_session_setup_lm21_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, char **out_native_os, char **out_native_lm); +struct tevent_req *smb1cli_session_setup_nt1_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct smbXcli_conn *conn, + uint32_t timeout_msec, + uint32_t pid, + struct smbXcli_session *session, + uint16_t in_buf_size, + uint16_t in_mpx_max, + uint16_t in_vc_num, + uint32_t in_sess_key, + const char *in_user, + const char *in_domain, + const DATA_BLOB in_apassword, + const DATA_BLOB in_upassword, + uint32_t in_capabilities, + const char *in_native_os, + const char *in_native_lm); +NTSTATUS smb1cli_session_setup_nt1_recv(struct tevent_req *req, + TALLOC_CTX *mem_ctx, + struct iovec **precv_iov, + const uint8_t **precv_inbuf, + char **out_native_os, + char **out_native_lm, + char **out_primary_domain); struct tevent_req *smb1cli_ntcreatex_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, |