/* Unix SMB/CIFS implementation. client connect/disconnect routines Copyright (C) Andrew Tridgell 1994-1998 Copyright (C) Andrew Bartlett 2001-2003 Copyright (C) Volker Lendecke 2011 Copyright (C) Jeremy Allison 2011 Copyright (C) Stefan Metzmacher 2016 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "includes.h" #include "system/network.h" #include "../lib/util/tevent_ntstatus.h" #include "../libcli/smb/smb_common.h" #include "../libcli/smb/smbXcli_base.h" struct smb1cli_session_setup_lm21_state { struct smbXcli_session *session; uint16_t vwv[10]; struct iovec *recv_iov; uint16_t out_session_id; uint16_t out_action; char *out_native_os; char *out_native_lm; }; static void smb1cli_session_setup_lm21_done(struct tevent_req *subreq); struct tevent_req *smb1cli_session_setup_lm21_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 char *in_native_os, const char *in_native_lm) { struct tevent_req *req = NULL; struct smb1cli_session_setup_lm21_state *state = NULL; struct tevent_req *subreq = NULL; uint16_t *vwv = NULL; uint8_t *bytes = NULL; req = tevent_req_create(mem_ctx, &state, struct smb1cli_session_setup_lm21_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_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, 0); /* reserved */ SSVAL(vwv+9, 0, 0); /* reserved */ bytes = talloc_array(state, uint8_t, in_apassword.length); if (tevent_req_nomem(bytes, req)) { return tevent_req_post(req, ev); } if (in_apassword.length != 0) { memcpy(bytes, in_apassword.data, in_apassword.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, 10, /* 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_lm21_done, req); return req; } static void smb1cli_session_setup_lm21_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); struct smb1cli_session_setup_lm21_state *state = tevent_req_data(req, struct smb1cli_session_setup_lm21_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 */ NULL, /* pinbuf */ 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; 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_lm21_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, char **out_native_os, char **out_native_lm) { struct smb1cli_session_setup_lm21_state *state = tevent_req_data(req, struct smb1cli_session_setup_lm21_state); NTSTATUS status; if (tevent_req_is_nterror(req, &status)) { tevent_req_received(req); return status; } 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); } tevent_req_received(req); return NT_STATUS_OK; }