diff options
Diffstat (limited to 'source3/libsmb')
-rw-r--r-- | source3/libsmb/async_smb.c | 1117 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 450 | ||||
-rw-r--r-- | source3/libsmb/clientgen.c | 183 | ||||
-rw-r--r-- | source3/libsmb/clierror.c | 16 | ||||
-rw-r--r-- | source3/libsmb/clifsinfo.c | 15 | ||||
-rw-r--r-- | source3/libsmb/clisigning.c | 54 | ||||
-rw-r--r-- | source3/libsmb/proto.h | 5 | ||||
-rw-r--r-- | source3/libsmb/smb2cli_base.h | 14 | ||||
-rw-r--r-- | source3/libsmb/smb2cli_negprot.c | 14 | ||||
-rw-r--r-- | source3/libsmb/smb2cli_session.c | 8 |
10 files changed, 243 insertions, 1633 deletions
diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index 574ca3b2ba..721ac9bfe4 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -19,294 +19,18 @@ #include "includes.h" #include "libsmb/libsmb.h" -#include "../lib/async_req/async_sock.h" #include "../lib/util/tevent_ntstatus.h" -#include "../lib/util/tevent_unix.h" #include "async_smb.h" -#include "../libcli/smb/smb_seal.h" -#include "libsmb/nmblib.h" -#include "../libcli/smb/read_smb.h" - -static NTSTATUS cli_pull_raw_error(const uint8_t *buf) -{ - const uint8_t *hdr = buf + NBT_HDR_SIZE; - uint32_t flags2 = SVAL(hdr, HDR_FLG2); - NTSTATUS status = NT_STATUS(IVAL(hdr, HDR_RCLS)); - - if (NT_STATUS_IS_OK(status)) { - return NT_STATUS_OK; - } - - if (flags2 & FLAGS2_32_BIT_ERROR_CODES) { - return status; - } - - return NT_STATUS_DOS(CVAL(hdr, HDR_RCLS), SVAL(hdr, HDR_ERR)); -} - -/** - * Figure out if there is an andx command behind the current one - * @param[in] buf The smb buffer to look at - * @param[in] ofs The offset to the wct field that is followed by the cmd - * @retval Is there a command following? - */ - -static bool have_andx_command(const char *buf, uint16_t ofs, uint8_t cmd) -{ - uint8_t wct; - size_t buflen = talloc_get_size(buf); - - if (!is_andx_req(cmd)) { - return false; - } - - if ((ofs == buflen-1) || (ofs == buflen)) { - return false; - } - - wct = CVAL(buf, ofs); - if (wct < 2) { - /* - * Not enough space for the command and a following pointer - */ - return false; - } - return (CVAL(buf, ofs+1) != 0xff); -} - -#define MAX_SMB_IOV 5 - -struct cli_smb_state { - struct tevent_context *ev; - struct cli_state *cli; - uint8_t header[smb_wct+1]; /* Space for the header including the wct */ - - /* - * For normal requests, cli_smb_req_send chooses a mid. Secondary - * trans requests need to use the mid of the primary request, so we - * need a place to store it. Assume it's set if != 0. - */ - uint16_t mid; - - uint16_t *vwv; - uint8_t bytecount_buf[2]; - - struct iovec iov[MAX_SMB_IOV+3]; - int iov_count; - - uint8_t *inbuf; - uint32_t seqnum; - int chain_num; - int chain_length; - struct tevent_req **chained_requests; - - bool one_way; -}; - -static uint16_t cli_alloc_mid(struct cli_state *cli) -{ - int num_pending = talloc_array_length(cli->conn.pending); - uint16_t result; - - while (true) { - int i; - - result = cli->conn.smb1.mid++; - if ((result == 0) || (result == 0xffff)) { - continue; - } - - for (i=0; i<num_pending; i++) { - if (result == cli_smb_req_mid(cli->conn.pending[i])) { - break; - } - } - - if (i == num_pending) { - return result; - } - } -} +#include "../libcli/smb/smbXcli_base.h" void cli_smb_req_unset_pending(struct tevent_req *req) { - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - struct cli_state *cli = state->cli; - int num_pending = talloc_array_length(cli->conn.pending); - int i; - - if (state->mid != 0) { - /* - * This is a [nt]trans[2] request which waits - * for more than one reply. - */ - return; - } - - talloc_set_destructor(req, NULL); - - if (num_pending == 1) { - /* - * The pending read_smb tevent_req is a child of - * cli->pending. So if nothing is pending anymore, we need to - * delete the socket read fde. - */ - TALLOC_FREE(cli->conn.pending); - cli->conn.read_smb_req = NULL; - return; - } - - for (i=0; i<num_pending; i++) { - if (req == cli->conn.pending[i]) { - break; - } - } - if (i == num_pending) { - /* - * Something's seriously broken. Just returning here is the - * right thing nevertheless, the point of this routine is to - * remove ourselves from cli->conn.pending. - */ - return; - } - - /* - * Remove ourselves from the cli->conn.pending array - */ - for (; i < (num_pending - 1); i++) { - cli->conn.pending[i] = cli->conn.pending[i+1]; - } - - /* - * No NULL check here, we're shrinking by sizeof(void *), and - * talloc_realloc just adjusts the size for this. - */ - cli->conn.pending = talloc_realloc(NULL, cli->conn.pending, - struct tevent_req *, - num_pending - 1); - return; + smbXcli_req_unset_pending(req); } -static int cli_smb_req_destructor(struct tevent_req *req) -{ - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - /* - * Make sure we really remove it from - * the pending array on destruction. - */ - state->mid = 0; - cli_smb_req_unset_pending(req); - return 0; -} - -static bool cli_state_receive_next(struct cli_state *cli); -static void cli_state_notify_pending(struct cli_state *cli, NTSTATUS status); - bool cli_smb_req_set_pending(struct tevent_req *req) { - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - struct cli_state *cli; - struct tevent_req **pending; - int num_pending; - - cli = state->cli; - num_pending = talloc_array_length(cli->conn.pending); - - pending = talloc_realloc(cli, cli->conn.pending, struct tevent_req *, - num_pending+1); - if (pending == NULL) { - return false; - } - pending[num_pending] = req; - cli->conn.pending = pending; - talloc_set_destructor(req, cli_smb_req_destructor); - - if (!cli_state_receive_next(cli)) { - /* - * the caller should notify the current request - * - * And all other pending requests get notified - * by cli_state_notify_pending(). - */ - cli_smb_req_unset_pending(req); - cli_state_notify_pending(cli, NT_STATUS_NO_MEMORY); - return false; - } - - return true; -} - -static void cli_smb_received(struct tevent_req *subreq); -static NTSTATUS cli_state_dispatch_smb1(struct cli_state *cli, - TALLOC_CTX *frame, - uint8_t *inbuf); - -static bool cli_state_receive_next(struct cli_state *cli) -{ - size_t num_pending = talloc_array_length(cli->conn.pending); - struct tevent_req *req; - struct cli_smb_state *state; - - if (cli->conn.read_smb_req != NULL) { - return true; - } - - if (num_pending == 0) { - return true; - } - - req = cli->conn.pending[0]; - state = tevent_req_data(req, struct cli_smb_state); - - cli->conn.dispatch_incoming = cli_state_dispatch_smb1; - - /* - * We're the first ones, add the read_smb request that waits for the - * answer from the server - */ - cli->conn.read_smb_req = read_smb_send(cli->conn.pending, state->ev, - cli->conn.fd); - if (cli->conn.read_smb_req == NULL) { - return false; - } - tevent_req_set_callback(cli->conn.read_smb_req, cli_smb_received, cli); - return true; -} - -static void cli_state_notify_pending(struct cli_state *cli, NTSTATUS status) -{ - cli_state_disconnect(cli); - - /* - * Cancel all pending requests. We do not do a for-loop walking - * cli->conn.pending because that array changes in - * cli_smb_req_destructor(). - */ - while (talloc_array_length(cli->conn.pending) > 0) { - struct tevent_req *req; - struct cli_smb_state *state; - - req = cli->conn.pending[0]; - state = tevent_req_data(req, struct cli_smb_state); - - /* - * We're dead. No point waiting for trans2 - * replies. - */ - state->mid = 0; - - cli_smb_req_unset_pending(req); - - /* - * we need to defer the callback, because we may notify more - * then one caller. - */ - tevent_req_defer_callback(req, state->ev); - tevent_req_nterror(req, status); - } + return smbXcli_req_set_pending(req); } /* @@ -315,65 +39,48 @@ static void cli_state_notify_pending(struct cli_state *cli, NTSTATUS status) */ uint16_t cli_smb_req_mid(struct tevent_req *req) { - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - - if (state->mid != 0) { - return state->mid; - } - - return SVAL(state->header, smb_mid); + return smb1cli_req_mid(req); } void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid) { - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - state->mid = mid; + smb1cli_req_set_mid(req, mid); } uint32_t cli_smb_req_seqnum(struct tevent_req *req) { - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - return state->seqnum; + return smb1cli_req_seqnum(req); } void cli_smb_req_set_seqnum(struct tevent_req *req, uint32_t seqnum) { - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - state->seqnum = seqnum; + smb1cli_req_set_seqnum(req, seqnum); } -static size_t iov_len(const struct iovec *iov, int count) +struct cli_smb_req_state { + struct cli_state *cli; + uint8_t smb_command; + struct tevent_req *req; + struct cli_smb_req_state **ptr; +}; + +static int cli_smb_req_state_destructor(struct cli_smb_req_state *state) { - size_t result = 0; - int i; - for (i=0; i<count; i++) { - result += iov[i].iov_len; - } - return result; + talloc_set_destructor(state->ptr, NULL); + talloc_free(state->ptr); + return 0; } -static uint8_t *iov_concat(TALLOC_CTX *mem_ctx, const struct iovec *iov, - int count) +static int cli_smb_req_state_ptr_destructor(struct cli_smb_req_state **ptr) { - size_t len = iov_len(iov, count); - size_t copied; - uint8_t *buf; - int i; + struct cli_smb_req_state *state = *ptr; + void *parent = talloc_parent(state); - buf = talloc_array(mem_ctx, uint8_t, len); - if (buf == NULL) { - return NULL; - } - copied = 0; - for (i=0; i<count; i++) { - memcpy(buf+copied, iov[i].iov_base, iov[i].iov_len); - copied += iov[i].iov_len; - } - return buf; + talloc_set_destructor(state, NULL); + + talloc_reparent(state, parent, state->req); + talloc_free(state); + return 0; } struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx, @@ -385,176 +92,58 @@ struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx, int iov_count, struct iovec *bytes_iov) { - struct tevent_req *result; - struct cli_smb_state *state; - struct timeval endtime; - - if (iov_count > MAX_SMB_IOV) { - /* - * Should not happen :-) - */ - return NULL; - } + struct cli_smb_req_state *state; + uint8_t clear_flags = 0; + uint16_t additional_flags2 = 0; + uint16_t clear_flags2 = 0; - result = tevent_req_create(mem_ctx, &state, struct cli_smb_state); - if (result == NULL) { + state = talloc_zero(mem_ctx, struct cli_smb_req_state); + if (state == NULL) { return NULL; } - state->ev = ev; state->cli = cli; - state->mid = 0; /* Set to auto-choose in cli_smb_req_send */ - state->chain_num = 0; - state->chained_requests = NULL; - - cli_setup_packet_buf(cli, (char *)state->header); - SCVAL(state->header, smb_com, smb_command); - SSVAL(state->header, smb_tid, cli->smb1.tid); - SCVAL(state->header, smb_wct, wct); - - state->vwv = vwv; - - SSVAL(state->bytecount_buf, 0, iov_len(bytes_iov, iov_count)); - - state->iov[0].iov_base = (void *)state->header; - state->iov[0].iov_len = sizeof(state->header); - state->iov[1].iov_base = (void *)state->vwv; - state->iov[1].iov_len = wct * sizeof(uint16_t); - state->iov[2].iov_base = (void *)state->bytecount_buf; - state->iov[2].iov_len = sizeof(uint16_t); - - if (iov_count != 0) { - memcpy(&state->iov[3], bytes_iov, - iov_count * sizeof(*bytes_iov)); - } - state->iov_count = iov_count + 3; - - if (cli->timeout) { - endtime = timeval_current_ofs_msec(cli->timeout); - if (!tevent_req_set_endtime(result, ev, endtime)) { - return result; - } - } - - switch (smb_command) { - case SMBtranss: - case SMBtranss2: - case SMBnttranss: - case SMBntcancel: - state->one_way = true; - break; - case SMBlockingX: - if ((wct == 8) && - (CVAL(vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) { - state->one_way = true; - } - break; - } - - return result; -} - -static NTSTATUS cli_signv(struct cli_state *cli, struct iovec *iov, int count, - uint32_t *seqnum) -{ - uint8_t *buf; - - /* - * Obvious optimization: Make cli_calculate_sign_mac work with struct - * iovec directly. MD5Update would do that just fine. - */ - - if ((count <= 0) || (iov[0].iov_len < smb_wct)) { - return NT_STATUS_INVALID_PARAMETER; - } - - buf = iov_concat(talloc_tos(), iov, count); - if (buf == NULL) { - return NT_STATUS_NO_MEMORY; - } - - cli_calculate_sign_mac(cli, (char *)buf, seqnum); - memcpy(iov[0].iov_base, buf, iov[0].iov_len); - - TALLOC_FREE(buf); - return NT_STATUS_OK; -} - -static void cli_smb_sent(struct tevent_req *subreq); - -static NTSTATUS cli_smb_req_iov_send(struct tevent_req *req, - struct cli_smb_state *state, - struct iovec *iov, int iov_count) -{ - struct tevent_req *subreq; - NTSTATUS status; - - if (!cli_state_is_connected(state->cli)) { - return NT_STATUS_CONNECTION_DISCONNECTED; - } - - if (iov[0].iov_len < smb_wct) { - return NT_STATUS_INVALID_PARAMETER; + state->smb_command = smb_command; + state->ptr = talloc(state, struct cli_smb_req_state *); + if (state->ptr == NULL) { + talloc_free(state); + return NULL; } + *state->ptr = state; - if (state->mid != 0) { - SSVAL(iov[0].iov_base, smb_mid, state->mid); + if (cli->case_sensitive) { + clear_flags |= FLAG_CASELESS_PATHNAMES; } else { - uint16_t mid = cli_alloc_mid(state->cli); - SSVAL(iov[0].iov_base, smb_mid, mid); + /* Default setting, case insensitive. */ + additional_flags |= FLAG_CASELESS_PATHNAMES; } - smb_setlen_nbt((char *)iov[0].iov_base, iov_len(iov, iov_count) - 4); - - status = cli_signv(state->cli, iov, iov_count, &state->seqnum); + if ((cli_state_capabilities(cli) & CAP_DFS) && cli->dfsroot) { + additional_flags2 |= FLAGS2_DFS_PATHNAMES; + } - if (!NT_STATUS_IS_OK(status)) { - return status; + state->req = smb1cli_req_create(state, ev, cli->conn, smb_command, + additional_flags, clear_flags, + additional_flags2, clear_flags2, + cli->timeout, + cli->smb1.pid, + cli->smb1.tid, + cli->smb1.uid, + wct, vwv, iov_count, bytes_iov); + if (state->req == NULL) { + talloc_free(state); + return NULL; } - if (cli_state_encryption_on(state->cli)) { - char *buf, *enc_buf; + talloc_reparent(state, state->req, state->ptr); + talloc_set_destructor(state, cli_smb_req_state_destructor); + talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor); - buf = (char *)iov_concat(talloc_tos(), iov, iov_count); - if (buf == NULL) { - return NT_STATUS_NO_MEMORY; - } - status = common_encrypt_buffer(state->cli->trans_enc_state, - (char *)buf, &enc_buf); - TALLOC_FREE(buf); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Error in encrypting client message: %s\n", - nt_errstr(status))); - return status; - } - buf = (char *)talloc_memdup(state, enc_buf, - smb_len_nbt(enc_buf)+4); - SAFE_FREE(enc_buf); - if (buf == NULL) { - return NT_STATUS_NO_MEMORY; - } - iov[0].iov_base = (void *)buf; - iov[0].iov_len = talloc_get_size(buf); - iov_count = 1; - } - subreq = writev_send(state, state->ev, state->cli->conn.outgoing, - state->cli->conn.fd, false, iov, iov_count); - if (subreq == NULL) { - return NT_STATUS_NO_MEMORY; - } - tevent_req_set_callback(subreq, cli_smb_sent, req); - return NT_STATUS_OK; + return state->req; } NTSTATUS cli_smb_req_send(struct tevent_req *req) { - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - - if (!tevent_req_is_in_progress(req)) { - return NT_STATUS_INTERNAL_ERROR; - } - - return cli_smb_req_iov_send(req, state, state->iov, state->iov_count); + return smb1cli_req_chain_submit(&req, 1); } struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx, @@ -566,259 +155,53 @@ struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx, uint32_t num_bytes, const uint8_t *bytes) { - struct tevent_req *req; - struct iovec iov; - NTSTATUS status; - - iov.iov_base = discard_const_p(void, bytes); - iov.iov_len = num_bytes; + struct cli_smb_req_state *state; + uint8_t clear_flags = 0; + uint16_t additional_flags2 = 0; + uint16_t clear_flags2 = 0; - req = cli_smb_req_create(mem_ctx, ev, cli, smb_command, - additional_flags, wct, vwv, 1, &iov); - if (req == NULL) { + state = talloc_zero(mem_ctx, struct cli_smb_req_state); + if (state == NULL) { return NULL; } - if (!tevent_req_is_in_progress(req)) { - return tevent_req_post(req, ev); - } - status = cli_smb_req_send(req); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); - } - return req; -} - -static void cli_smb_sent(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - ssize_t nwritten; - int err; - - nwritten = writev_recv(subreq, &err); - TALLOC_FREE(subreq); - if (nwritten == -1) { - NTSTATUS status = map_nt_error_from_unix_common(err); - cli_state_notify_pending(state->cli, status); - return; - } - - if (state->one_way) { - state->inbuf = NULL; - tevent_req_done(req); - return; - } - - if (!cli_smb_req_set_pending(req)) { - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return; - } -} - -static void cli_smb_received(struct tevent_req *subreq) -{ - struct cli_state *cli = tevent_req_callback_data( - subreq, struct cli_state); - TALLOC_CTX *frame = talloc_stackframe(); - NTSTATUS status; - uint8_t *inbuf; - ssize_t received; - int err; - - if (subreq != cli->conn.read_smb_req) { - DEBUG(1, ("Internal error: cli_smb_received called with " - "unexpected subreq\n")); - status = NT_STATUS_INTERNAL_ERROR; - cli_state_notify_pending(cli, status); - TALLOC_FREE(frame); - return; - } - - received = read_smb_recv(subreq, frame, &inbuf, &err); - TALLOC_FREE(subreq); - cli->conn.read_smb_req = NULL; - if (received == -1) { - status = map_nt_error_from_unix_common(err); - cli_state_notify_pending(cli, status); - TALLOC_FREE(frame); - return; - } - - status = cli->conn.dispatch_incoming(cli, frame, inbuf); - TALLOC_FREE(frame); - if (NT_STATUS_IS_OK(status)) { - /* - * We should not do any more processing - * as the dispatch function called - * tevent_req_done(). - */ - return; - } else if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { - /* - * We got an error, so notify all pending requests - */ - cli_state_notify_pending(cli, status); - return; - } - - /* - * We got NT_STATUS_RETRY, so we may ask for a - * next incoming pdu. - */ - if (!cli_state_receive_next(cli)) { - cli_state_notify_pending(cli, NT_STATUS_NO_MEMORY); - } -} - -static NTSTATUS cli_state_dispatch_smb1(struct cli_state *cli, - TALLOC_CTX *frame, - uint8_t *inbuf) -{ - struct tevent_req *req; - struct cli_smb_state *state; - NTSTATUS status; - int num_pending; - int i; - uint16_t mid; - bool oplock_break; - const uint8_t *inhdr = inbuf + NBT_HDR_SIZE; - - if ((IVAL(inhdr, 0) != SMB_MAGIC) /* 0xFF"SMB" */ - && (SVAL(inhdr, 0) != 0x45ff)) /* 0xFF"E" */ { - DEBUG(10, ("Got non-SMB PDU\n")); - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - if (cli_state_encryption_on(cli) && (CVAL(inbuf, 0) == 0)) { - uint16_t enc_ctx_num; - - status = get_enc_ctx_num(inbuf, &enc_ctx_num); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("get_enc_ctx_num returned %s\n", - nt_errstr(status))); - return status; - } - - if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) { - DEBUG(10, ("wrong enc_ctx %d, expected %d\n", - enc_ctx_num, - cli->trans_enc_state->enc_ctx_num)); - return NT_STATUS_INVALID_HANDLE; - } - - status = common_decrypt_buffer(cli->trans_enc_state, - (char *)inbuf); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("common_decrypt_buffer returned %s\n", - nt_errstr(status))); - return status; - } - } - - mid = SVAL(inhdr, HDR_MID); - num_pending = talloc_array_length(cli->conn.pending); - - for (i=0; i<num_pending; i++) { - if (mid == cli_smb_req_mid(cli->conn.pending[i])) { - break; - } - } - if (i == num_pending) { - /* Dump unexpected reply */ - return NT_STATUS_RETRY; + state->cli = cli; + state->smb_command = smb_command; + state->ptr = talloc(state, struct cli_smb_req_state *); + if (state->ptr == NULL) { + talloc_free(state); + return NULL; } + *state->ptr = state; - oplock_break = false; - - if (mid == 0xffff) { - /* - * Paranoia checks that this is really an oplock break request. - */ - oplock_break = (smb_len_nbt(inbuf) == 51); /* hdr + 8 words */ - oplock_break &= ((CVAL(inhdr, HDR_FLG) & FLAG_REPLY) == 0); - oplock_break &= (CVAL(inhdr, HDR_COM) == SMBlockingX); - oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(6)) == 0); - oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(7)) == 0); - - if (!oplock_break) { - /* Dump unexpected reply */ - return NT_STATUS_RETRY; - } + if (cli->case_sensitive) { + clear_flags |= FLAG_CASELESS_PATHNAMES; + } else { + /* Default setting, case insensitive. */ + additional_flags |= FLAG_CASELESS_PATHNAMES; } - req = cli->conn.pending[i]; - state = tevent_req_data(req, struct cli_smb_state); - - if (!oplock_break /* oplock breaks are not signed */ - && !cli_check_sign_mac(cli, (char *)inbuf, state->seqnum+1)) { - DEBUG(10, ("cli_check_sign_mac failed\n")); - return NT_STATUS_ACCESS_DENIED; + if ((cli_state_capabilities(cli) & CAP_DFS) && cli->dfsroot) { + additional_flags2 |= FLAGS2_DFS_PATHNAMES; } - if (state->chained_requests != NULL) { - struct tevent_req **chain = talloc_move(frame, - &state->chained_requests); - int num_chained = talloc_array_length(chain); - - /* - * We steal the inbuf to the chain, - * so that it will stay until all - * requests of the chain are finished. - * - * Each requests in the chain will - * hold a talloc reference to the chain. - * This way we do not expose the talloc_reference() - * behavior to the callers. - */ - talloc_steal(chain, inbuf); - - for (i=0; i<num_chained; i++) { - struct tevent_req **ref; - - req = chain[i]; - state = tevent_req_data(req, struct cli_smb_state); - - cli_smb_req_unset_pending(req); - - /* - * as we finish multiple requests here - * we need to defer the callbacks as - * they could destroy our current stack state. - */ - tevent_req_defer_callback(req, state->ev); - - ref = talloc_reference(state, chain); - if (tevent_req_nomem(ref, req)) { - continue; - } - - state->inbuf = inbuf; - state->chain_num = i; - state->chain_length = num_chained; - - tevent_req_done(req); - } - - return NT_STATUS_RETRY; + state->req = smb1cli_req_send(state, ev, cli->conn, smb_command, + additional_flags, clear_flags, + additional_flags2, clear_flags2, + cli->timeout, + cli->smb1.pid, + cli->smb1.tid, + cli->smb1.uid, + wct, vwv, num_bytes, bytes); + if (state->req == NULL) { + talloc_free(state); + return NULL; } - cli_smb_req_unset_pending(req); - - state->inbuf = talloc_move(state, &inbuf); - state->chain_num = 0; - state->chain_length = 1; + talloc_reparent(state, state->req, state->ptr); + talloc_set_destructor(state, cli_smb_req_state_destructor); + talloc_set_destructor(state->ptr, cli_smb_req_state_ptr_destructor); - if (talloc_array_length(cli->conn.pending) == 0) { - tevent_req_done(req); - return NT_STATUS_OK; - } - - tevent_req_defer_callback(req, state->ev); - tevent_req_done(req); - return NT_STATUS_RETRY; + return state->req; } NTSTATUS cli_smb_recv(struct tevent_req *req, @@ -826,81 +209,68 @@ NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv, uint32_t *pnum_bytes, uint8_t **pbytes) { - struct cli_smb_state *state = tevent_req_data( - req, struct cli_smb_state); - NTSTATUS status = NT_STATUS_OK; - uint8_t cmd, wct; - uint16_t num_bytes; - size_t wct_ofs, bytes_offset; - int i; + NTSTATUS status; + void *parent = talloc_parent(req); + struct cli_smb_req_state *state = + talloc_get_type(parent, + struct cli_smb_req_state); + struct iovec *recv_iov = NULL; + uint8_t wct = 0; + uint16_t *vwv = NULL; + uint32_t num_bytes; + uint8_t *bytes = NULL; + uint8_t *inbuf; + bool is_expected = false; + bool map_dos_errors = true; - if (tevent_req_is_nterror(req, &status)) { - return status; + if (pinbuf != NULL) { + *pinbuf = NULL; } - - if (state->inbuf == NULL) { - if (min_wct != 0) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - if (pinbuf) { - *pinbuf = NULL; - } - if (pwct) { - *pwct = 0; - } - if (pvwv) { - *pvwv = NULL; - } - if (pnum_bytes) { - *pnum_bytes = 0; - } - if (pbytes) { - *pbytes = NULL; - } - /* This was a request without a reply */ - return NT_STATUS_OK; + if (pwct != NULL) { + *pwct = 0; } - - wct_ofs = smb_wct; - cmd = CVAL(state->inbuf, smb_com); - - for (i=0; i<state->chain_num; i++) { - if (i < state->chain_num-1) { - if (cmd == 0xff) { - return NT_STATUS_REQUEST_ABORTED; - } - if (!is_andx_req(cmd)) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - } - - if (!have_andx_command((char *)state->inbuf, wct_ofs, cmd)) { + if (pvwv != NULL) { + *pvwv = NULL; + } + if (pnum_bytes != NULL) { + *pnum_bytes = 0; + } + if (pbytes != NULL) { + *pbytes = NULL; + } + + status = smb1cli_req_recv(req, req, + &recv_iov, + NULL, /* phdr */ + &wct, + &vwv, + NULL, /* pvwv_offset */ + &num_bytes, + &bytes, + NULL, /* pbytes_offset */ + &inbuf, + NULL, 0); /* expected */ + + if (state) { + if ((state->smb_command == SMBsesssetupX) && + NT_STATUS_EQUAL(status, + NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* - * This request was not completed because a previous - * request in the chain had received an error. + * NT_STATUS_MORE_PROCESSING_REQUIRED is a + * valid return code for session setup */ - return NT_STATUS_REQUEST_ABORTED; + is_expected = true; } - cmd = CVAL(state->inbuf, wct_ofs + 1); - wct_ofs = SVAL(state->inbuf, wct_ofs + 3); - - /* - * Skip the all-present length field. No overflow, we've just - * put a 16-bit value into a size_t. - */ - wct_ofs += 4; - - if (wct_ofs+2 > talloc_get_size(state->inbuf)) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } + map_dos_errors = state->cli->map_dos_errors; + state->cli->raw_status = status; + talloc_free(state->ptr); + state = NULL; } - state->cli->raw_status = cli_pull_raw_error(state->inbuf); - if (NT_STATUS_IS_DOS(state->cli->raw_status) && - state->cli->map_dos_errors) { - uint8_t eclass = NT_STATUS_DOS_CLASS(state->cli->raw_status); - uint16_t ecode = NT_STATUS_DOS_CODE(state->cli->raw_status); + if (NT_STATUS_IS_DOS(status) && map_dos_errors) { + uint8_t eclass = NT_STATUS_DOS_CLASS(status); + uint16_t ecode = NT_STATUS_DOS_CODE(status); /* * TODO: is it really a good idea to do a mapping here? * @@ -908,55 +278,19 @@ NTSTATUS cli_smb_recv(struct tevent_req *req, * the behavior yet. */ status = dos_to_ntstatus(eclass, ecode); - } else { - status = state->cli->raw_status; } - if (!have_andx_command((char *)state->inbuf, wct_ofs, cmd)) { - - if ((cmd == SMBsesssetupX) - && NT_STATUS_EQUAL( - status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - /* - * NT_STATUS_MORE_PROCESSING_REQUIRED is a - * valid return code for session setup - */ - goto no_err; - } - - if (NT_STATUS_IS_ERR(status)) { - /* - * The last command takes the error code. All - * further commands down the requested chain - * will get a NT_STATUS_REQUEST_ABORTED. - */ - return status; - } - } else { - /* - * Only the last request in the chain get the returned - * status. - */ - status = NT_STATUS_OK; + if (!NT_STATUS_IS_ERR(status)) { + is_expected = true; } -no_err: - - wct = CVAL(state->inbuf, wct_ofs); - bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t); - num_bytes = SVAL(state->inbuf, bytes_offset); - - if (wct < min_wct) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; + if (!is_expected) { + TALLOC_FREE(recv_iov); + return status; } - /* - * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes - * is a 16-bit value. So bytes_offset being size_t should be far from - * wrapping. - */ - if ((bytes_offset + 2 > talloc_get_size(state->inbuf)) - || (bytes_offset > 0xffff)) { + if (wct < min_wct) { + TALLOC_FREE(recv_iov); return NT_STATUS_INVALID_NETWORK_RESPONSE; } @@ -964,19 +298,21 @@ no_err: *pwct = wct; } if (pvwv != NULL) { - *pvwv = (uint16_t *)(state->inbuf + wct_ofs + 1); + *pvwv = vwv; } if (pnum_bytes != NULL) { *pnum_bytes = num_bytes; } if (pbytes != NULL) { - *pbytes = (uint8_t *)state->inbuf + bytes_offset + 2; + *pbytes = bytes; } - if ((mem_ctx != NULL) && (pinbuf != NULL)) { - if (state->chain_num == state->chain_length-1) { - *pinbuf = talloc_move(mem_ctx, &state->inbuf); + + if (pinbuf != NULL && mem_ctx != NULL) { + if (talloc_reference_count(inbuf) == 0) { + *pinbuf = talloc_move(mem_ctx, &inbuf); + TALLOC_FREE(recv_iov); } else { - *pinbuf = state->inbuf; + *pinbuf = inbuf; } } @@ -985,134 +321,15 @@ no_err: size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs) { - size_t wct_ofs; - int i; - - wct_ofs = smb_wct - 4; - - for (i=0; i<num_reqs; i++) { - struct cli_smb_state *state; - state = tevent_req_data(reqs[i], struct cli_smb_state); - wct_ofs += iov_len(state->iov+1, state->iov_count-1); - wct_ofs = (wct_ofs + 3) & ~3; - } - return wct_ofs; + return smb1cli_req_wct_ofs(reqs, num_reqs); } NTSTATUS cli_smb_chain_send(struct tevent_req **reqs, int num_reqs) { - struct cli_smb_state *first_state = tevent_req_data( - reqs[0], struct cli_smb_state); - struct cli_smb_state *last_state = tevent_req_data( - reqs[num_reqs-1], struct cli_smb_state); - struct cli_smb_state *state; - size_t wct_offset; - size_t chain_padding = 0; - int i, iovlen; - struct iovec *iov = NULL; - struct iovec *this_iov; - NTSTATUS status; - - iovlen = 0; - for (i=0; i<num_reqs; i++) { - if (!tevent_req_is_in_progress(reqs[i])) { - return NT_STATUS_INTERNAL_ERROR; - } - - state = tevent_req_data(reqs[i], struct cli_smb_state); - iovlen += state->iov_count; - } - - iov = talloc_array(last_state, struct iovec, iovlen); - if (iov == NULL) { - return NT_STATUS_NO_MEMORY; - } - - first_state->chained_requests = (struct tevent_req **)talloc_memdup( - last_state, reqs, sizeof(*reqs) * num_reqs); - if (first_state->chained_requests == NULL) { - TALLOC_FREE(iov); - return NT_STATUS_NO_MEMORY; - } - - wct_offset = smb_wct - 4; - this_iov = iov; - - for (i=0; i<num_reqs; i++) { - size_t next_padding = 0; - uint16_t *vwv; - - state = tevent_req_data(reqs[i], struct cli_smb_state); - - if (i < num_reqs-1) { - if (!is_andx_req(CVAL(state->header, smb_com)) - || CVAL(state->header, smb_wct) < 2) { - TALLOC_FREE(iov); - TALLOC_FREE(first_state->chained_requests); - return NT_STATUS_INVALID_PARAMETER; - } - } - - wct_offset += iov_len(state->iov+1, state->iov_count-1) + 1; - if ((wct_offset % 4) != 0) { - next_padding = 4 - (wct_offset % 4); - } - wct_offset += next_padding; - vwv = state->vwv; - - if (i < num_reqs-1) { - struct cli_smb_state *next_state = tevent_req_data( - reqs[i+1], struct cli_smb_state); - SCVAL(vwv+0, 0, CVAL(next_state->header, smb_com)); - SCVAL(vwv+0, 1, 0); - SSVAL(vwv+1, 0, wct_offset); - } else if (is_andx_req(CVAL(state->header, smb_com))) { - /* properly end the chain */ - SCVAL(vwv+0, 0, 0xff); - SCVAL(vwv+0, 1, 0xff); - SSVAL(vwv+1, 0, 0); - } - - if (i == 0) { - this_iov[0] = state->iov[0]; - } else { - /* - * This one is a bit subtle. We have to add - * chain_padding bytes between the requests, and we - * have to also include the wct field of the - * subsequent requests. We use the subsequent header - * for the padding, it contains the wct field in its - * last byte. - */ - this_iov[0].iov_len = chain_padding+1; - this_iov[0].iov_base = (void *)&state->header[ - sizeof(state->header) - this_iov[0].iov_len]; - memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1); - } - memcpy(this_iov+1, state->iov+1, - sizeof(struct iovec) * (state->iov_count-1)); - this_iov += state->iov_count; - chain_padding = next_padding; - } - - status = cli_smb_req_iov_send(reqs[0], last_state, iov, iovlen); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(iov); - TALLOC_FREE(first_state->chained_requests); - return status; - } - - for (i=0; i < (num_reqs - 1); i++) { - state = tevent_req_data(reqs[i], struct cli_smb_state); - - state->seqnum = last_state->seqnum; - } - - return NT_STATUS_OK; + return smb1cli_req_chain_submit(reqs, num_reqs); } bool cli_has_async_calls(struct cli_state *cli) { - return ((tevent_queue_length(cli->conn.outgoing) != 0) - || (talloc_array_length(cli->conn.pending) != 0)); + return smbXcli_conn_has_async_calls(cli->conn); } diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index c2fa9239ef..8197e0ac18 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -33,22 +33,7 @@ #include "async_smb.h" #include "libsmb/nmblib.h" #include "librpc/ndr/libndr.h" - -static const struct { - int prot; - const char name[24]; -} prots[10] = { - {PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"}, - {PROTOCOL_COREPLUS, "MICROSOFT NETWORKS 1.03"}, - {PROTOCOL_LANMAN1, "MICROSOFT NETWORKS 3.0"}, - {PROTOCOL_LANMAN1, "LANMAN1.0"}, - {PROTOCOL_LANMAN2, "LM1.2X002"}, - {PROTOCOL_LANMAN2, "DOS LANMAN2.1"}, - {PROTOCOL_LANMAN2, "LANMAN2.1"}, - {PROTOCOL_LANMAN2, "Samba"}, - {PROTOCOL_NT1, "NT LANMAN 1.0"}, - {PROTOCOL_NT1, "NT LM 0.12"}, -}; +#include "../libcli/smb/smbXcli_base.h" #define STAR_SMBSERVER "*SMBSERVER" @@ -2513,446 +2498,25 @@ fail: return status; } -/**************************************************************************** - Send a negprot command. -****************************************************************************/ - -struct cli_negprot_state { - struct cli_state *cli; - enum protocol_types max_protocol; -}; - -static void cli_negprot_done(struct tevent_req *subreq); - struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct cli_state *cli, enum protocol_types max_protocol) { - struct tevent_req *req, *subreq; - struct cli_negprot_state *state; - uint8_t *bytes = NULL; - int numprots; - enum protocol_types tmp_protocol; - - req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state); - if (req == NULL) { - return NULL; - } - state->cli = cli; - state->max_protocol = max_protocol; - - /* setup the protocol strings */ - for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) { - uint8_t c = 2; - if (prots[numprots].prot > state->max_protocol) { - break; - } - bytes = (uint8_t *)talloc_append_blob( - state, bytes, data_blob_const(&c, sizeof(c))); - if (tevent_req_nomem(bytes, req)) { - return tevent_req_post(req, ev); - } - bytes = smb_bytes_push_str(bytes, false, - prots[numprots].name, - strlen(prots[numprots].name)+1, - NULL); - if (tevent_req_nomem(bytes, req)) { - return tevent_req_post(req, ev); - } - } - - tmp_protocol = cli->conn.protocol; - cli->conn.protocol = state->max_protocol; - subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL, - talloc_get_size(bytes), bytes); - cli->conn.protocol = tmp_protocol; - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, cli_negprot_done, req); - return req; -} - -static void cli_negprot_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_negprot_state *state = tevent_req_data( - req, struct cli_negprot_state); - struct cli_state *cli = state->cli; - uint8_t flags; - uint8_t wct; - uint16_t *vwv; - uint32_t num_bytes; - uint8_t *bytes; - NTSTATUS status; - uint16_t protnum; - uint8_t *inbuf; - uint32_t client_capabilities = cli->conn.smb1.client.capabilities; - uint32_t both_capabilities; - uint32_t server_capabilities = 0; - uint32_t capabilities; - uint32_t client_max_xmit = cli->conn.smb1.client.max_xmit; - uint32_t server_max_xmit = 0; - uint32_t max_xmit; - uint32_t server_max_mux = 0; - uint16_t server_security_mode = 0; - uint32_t server_session_key = 0; - bool server_readbraw = false; - bool server_writebraw = false; - bool server_lockread = false; - bool server_writeunlock = false; - struct GUID server_guid = GUID_zero(); - DATA_BLOB server_gss_blob = data_blob_null; - uint8_t server_challenge[8]; - char *server_workgroup = NULL; - char *server_name = NULL; - int server_time_zone = 0; - time_t server_system_time = 0; - enum protocol_types protocol; - - ZERO_STRUCT(server_challenge); - - status = cli_smb_recv(subreq, state, &inbuf, 1, &wct, &vwv, - &num_bytes, &bytes); - TALLOC_FREE(subreq); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(req, status); - return; - } - - flags = CVAL(inbuf, smb_flg); - - protnum = SVAL(vwv, 0); - - if ((protnum >= ARRAY_SIZE(prots)) - || (prots[protnum].prot > state->max_protocol)) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - protocol = prots[protnum].prot; - - if ((protocol < PROTOCOL_NT1) && - client_is_signing_mandatory(cli)) { - DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n")); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - - if (flags & FLAG_SUPPORT_LOCKREAD) { - server_lockread = true; - server_writeunlock = true; - } - - if (protocol >= PROTOCOL_NT1) { - struct timespec ts; - const char *client_signing = NULL; - bool server_mandatory; - bool server_allowed; - const char *server_signing = NULL; - bool ok; - uint8_t key_len; - - if (wct != 0x11) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - /* NT protocol */ - server_security_mode = CVAL(vwv + 1, 0); - server_max_mux = SVAL(vwv + 1, 1); - server_max_xmit = IVAL(vwv + 3, 1); - server_session_key = IVAL(vwv + 7, 1); - server_time_zone = SVALS(vwv + 15, 1); - server_time_zone *= 60; - /* this time arrives in real GMT */ - ts = interpret_long_date(((char *)(vwv+11))+1); - server_system_time = ts.tv_sec; - server_capabilities = IVAL(vwv + 9, 1); - - key_len = CVAL(vwv + 16, 1); - - if (server_capabilities & CAP_RAW_MODE) { - server_readbraw = true; - server_writebraw = true; - } - if (server_capabilities & CAP_LOCK_AND_READ) { - server_lockread = true; - } - - if (server_capabilities & CAP_EXTENDED_SECURITY) { - DATA_BLOB blob1, blob2; - - if (num_bytes < 16) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - blob1 = data_blob_const(bytes, 16); - GUID_from_data_blob(&blob1, &server_guid); - - blob1 = data_blob_const(bytes+16, num_bytes-16); - blob2 = data_blob_dup_talloc(state, blob1); - if (blob1.length > 0 && - tevent_req_nomem(blob2.data, req)) { - return; - } - server_gss_blob = blob2; - } else { - DATA_BLOB blob1, blob2; - ssize_t ret = 0; - - if (num_bytes < key_len) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - if (key_len != 0 && key_len != 8) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - if (key_len == 8) { - memcpy(server_challenge, bytes, 8); - } - - blob1 = data_blob_const(bytes+key_len, num_bytes-key_len); - blob2 = data_blob_const(bytes+key_len, num_bytes-key_len); - if (blob1.length > 0) { - ret = pull_string_talloc(state, - (char *)inbuf, - SVAL(inbuf, smb_flg2), - &server_workgroup, - blob1.data, - blob1.length, - STR_TERMINATE| - STR_UNICODE| - STR_NOALIGN); - if (ret == -1) { - tevent_req_oom(req); - return; - } - } - - blob2.data += ret; - blob2.length -= ret; - if (blob2.length > 0) { - ret = pull_string_talloc(state, - (char *)inbuf, - SVAL(inbuf, smb_flg2), - &server_name, - blob2.data, - blob2.length, - STR_TERMINATE| - STR_UNICODE| - STR_NOALIGN); - if (ret == -1) { - tevent_req_oom(req); - return; - } - } - } - - client_signing = "disabled"; - if (client_is_signing_allowed(cli)) { - client_signing = "allowed"; - } - if (client_is_signing_mandatory(cli)) { - client_signing = "required"; - } - - server_signing = "not supported"; - - server_allowed = false; - if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { - server_signing = "supported"; - server_allowed = true; - } - - server_mandatory = false; - if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) { - server_signing = "required"; - server_mandatory = true; - } - - ok = cli_set_signing_negotiated(cli, - server_allowed, - server_mandatory); - if (!ok) { - DEBUG(1,("cli_negprot: SMB signing is required, " - "but client[%s] and server[%s] mismatch\n", - client_signing, server_signing)); - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - - } else if (protocol >= PROTOCOL_LANMAN1) { - DATA_BLOB blob1; - ssize_t ret = 0; - uint16_t key_len; - - if (wct != 0x0D) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - server_security_mode = SVAL(vwv + 1, 0); - server_max_xmit = SVAL(vwv + 2, 0); - server_max_mux = SVAL(vwv + 3, 0); - server_readbraw = ((SVAL(vwv + 5, 0) & 0x1) != 0); - server_writebraw = ((SVAL(vwv + 5, 0) & 0x2) != 0); - server_session_key = IVAL(vwv + 6, 0); - server_time_zone = SVALS(vwv + 10, 0); - server_time_zone *= 60; - /* this time is converted to GMT by make_unix_date */ - server_system_time = make_unix_date( - (char *)(vwv + 8), server_time_zone); - key_len = SVAL(vwv + 11, 0); - - if (num_bytes < key_len) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - if (key_len != 0 && key_len != 8) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - if (key_len == 8) { - memcpy(server_challenge, bytes, 8); - } - - blob1 = data_blob_const(bytes+key_len, num_bytes-key_len); - if (blob1.length > 0) { - ret = pull_string_talloc(state, - (char *)inbuf, - SVAL(inbuf, smb_flg2), - &server_workgroup, - blob1.data, - blob1.length, - STR_TERMINATE| - STR_ASCII); - if (ret == -1) { - tevent_req_oom(req); - return; - } - } - } else { - /* the old core protocol */ - server_time_zone = get_time_zone(time(NULL)); - server_system_time = 0; - server_max_xmit = 1024; - server_max_mux = 1; - server_security_mode = 0; - } - - if (server_max_xmit < 1024) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - if (server_max_mux < 1) { - tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; - } - - /* - * Now calculate the negotiated capabilities - * based on the mask for: - * - client only flags - * - flags used in both directions - * - server only flags - */ - both_capabilities = client_capabilities & server_capabilities; - capabilities = client_capabilities & SMB_CAP_CLIENT_MASK; - capabilities |= both_capabilities & SMB_CAP_BOTH_MASK; - capabilities |= server_capabilities & SMB_CAP_SERVER_MASK; - - max_xmit = MIN(client_max_xmit, server_max_xmit); - - if (server_workgroup) { - cli->server_domain = talloc_strdup(cli, server_workgroup); - if (tevent_req_nomem(cli->server_domain, req)) { - return; - } - } - - cli->conn.protocol = protocol; - - cli->conn.smb1.server.capabilities = server_capabilities; - cli->conn.smb1.capabilities = capabilities; - - cli->conn.smb1.server.max_xmit = server_max_xmit; - cli->conn.smb1.max_xmit = max_xmit; - - cli->conn.smb1.server.max_mux = server_max_mux; - - cli->conn.smb1.server.security_mode = server_security_mode; - - cli->conn.smb1.server.readbraw = server_readbraw; - cli->conn.smb1.server.writebraw = server_writebraw; - cli->conn.smb1.server.lockread = server_lockread; - cli->conn.smb1.server.writeunlock = server_writeunlock; - - cli->conn.smb1.server.session_key = server_session_key; - - talloc_steal(cli, server_gss_blob.data); - cli->conn.smb1.server.gss_blob = server_gss_blob; - cli->conn.smb1.server.guid = server_guid; - memcpy(cli->conn.smb1.server.challenge, server_challenge, 8); - cli->conn.smb1.server.workgroup = talloc_move(cli, &server_workgroup); - cli->conn.smb1.server.name = talloc_move(cli, &server_name); - - cli->conn.smb1.server.time_zone = server_time_zone; - cli->conn.smb1.server.system_time = server_system_time; - - tevent_req_done(req); + return smbXcli_negprot_send(mem_ctx, ev, + cli->conn, cli->timeout, + PROTOCOL_CORE, max_protocol); } NTSTATUS cli_negprot_recv(struct tevent_req *req) { - return tevent_req_simple_recv_ntstatus(req); + return smbXcli_negprot_recv(req); } NTSTATUS cli_negprot(struct cli_state *cli, enum protocol_types max_protocol) { - TALLOC_CTX *frame = talloc_stackframe(); - struct event_context *ev; - struct tevent_req *req; - NTSTATUS status = NT_STATUS_OK; - - if (cli_has_async_calls(cli)) { - /* - * Can't use sync call while an async call is in flight - */ - status = NT_STATUS_INVALID_PARAMETER; - goto fail; - } - - ev = event_context_init(frame); - if (ev == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - - req = cli_negprot_send(frame, ev, cli, max_protocol); - if (req == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - - if (!tevent_req_poll(req, ev)) { - status = map_nt_error_from_unix(errno); - goto fail; - } - - status = cli_negprot_recv(req); - fail: - TALLOC_FREE(frame); - return status; + return smbXcli_negprot(cli->conn, cli->timeout, + PROTOCOL_CORE, max_protocol); } static NTSTATUS cli_connect_sock(const char *host, int name_type, diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 215ad3fec4..fbce64f200 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -24,6 +24,7 @@ #include "../libcli/smb/smb_signing.h" #include "../libcli/smb/smb_seal.h" #include "async_smb.h" +#include "../libcli/smb/smbXcli_base.h" /******************************************************************* Setup the word count and byte count for a client smb message. @@ -57,43 +58,7 @@ unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout) bool cli_ucs2(struct cli_state *cli) { - return ((cli_state_capabilities(cli) & CAP_UNICODE) != 0); -} - -/**************************************************************************** - Setup basics in a outgoing packet. -****************************************************************************/ - -void cli_setup_packet_buf(struct cli_state *cli, char *buf) -{ - uint16 flags2; - cli->rap_error = 0; - SIVAL(buf,smb_rcls,0); - SSVAL(buf,smb_pid,cli->smb1.pid); - memset(buf+smb_pidhigh, 0, 12); - SSVAL(buf,smb_uid, cli_state_get_uid(cli)); - SSVAL(buf,smb_mid, 0); - - if (cli_state_protocol(cli) <= PROTOCOL_CORE) { - return; - } - - if (cli->case_sensitive) { - SCVAL(buf,smb_flg,0x0); - } else { - /* Default setting, case insensitive. */ - SCVAL(buf,smb_flg,0x8); - } - flags2 = FLAGS2_LONG_PATH_COMPONENTS; - if (cli_state_capabilities(cli) & CAP_UNICODE) - flags2 |= FLAGS2_UNICODE_STRINGS; - if ((cli_state_capabilities(cli) & CAP_DFS) && cli->dfsroot) - flags2 |= FLAGS2_DFS_PATHNAMES; - if (cli_state_capabilities(cli) & CAP_STATUS32) - flags2 |= FLAGS2_32_BIT_ERROR_CODES; - if (cli_state_capabilities(cli) & CAP_EXTENDED_SECURITY) - flags2 |= FLAGS2_EXTENDED_SECURITY; - SSVAL(buf,smb_flg2, flags2); + return smbXcli_conn_use_unicode(cli->conn); } /**************************************************************************** @@ -169,15 +134,11 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, int signing_state, int flags) { struct cli_state *cli = NULL; - bool allow_smb_signing; - bool desire_smb_signing; - bool mandatory_signing; - socklen_t ss_length; - int ret; bool use_spnego = lp_client_use_spnego(); bool force_dos_errors = false; bool force_ascii = false; bool use_level_II_oplocks = false; + uint32_t smb1_capabilities = 0; /* Check the effective uid - make sure we are not setuid */ if (is_setuid_root()) { @@ -254,100 +215,42 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, signing_state = lp_client_signing(); } - switch (signing_state) { - case SMB_SIGNING_OFF: - /* never */ - allow_smb_signing = false; - desire_smb_signing = false; - mandatory_signing = false; - break; - default: - case SMB_SIGNING_DEFAULT: - case SMB_SIGNING_IF_REQUIRED: - allow_smb_signing = true; - desire_smb_signing = false; - mandatory_signing = false; - break; - case SMB_SIGNING_REQUIRED: - /* always */ - allow_smb_signing = true; - desire_smb_signing = true; - mandatory_signing = true; - break; - } - - /* initialise signing */ - cli->signing_state = smb_signing_init(cli, - allow_smb_signing, - desire_smb_signing, - mandatory_signing); - if (!cli->signing_state) { - goto error; - } - - cli->conn.smb1.client.capabilities = 0; - cli->conn.smb1.client.capabilities |= CAP_LARGE_FILES; - cli->conn.smb1.client.capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS; - cli->conn.smb1.client.capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND; - cli->conn.smb1.client.capabilities |= CAP_DFS | CAP_W2K_SMBS; - cli->conn.smb1.client.capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX; - cli->conn.smb1.client.capabilities |= CAP_LWIO; + smb1_capabilities = 0; + smb1_capabilities |= CAP_LARGE_FILES; + smb1_capabilities |= CAP_NT_SMBS | CAP_RPC_REMOTE_APIS; + smb1_capabilities |= CAP_LOCK_AND_READ | CAP_NT_FIND; + smb1_capabilities |= CAP_DFS | CAP_W2K_SMBS; + smb1_capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX; + smb1_capabilities |= CAP_LWIO; if (!force_dos_errors) { - cli->conn.smb1.client.capabilities |= CAP_STATUS32; + smb1_capabilities |= CAP_STATUS32; } if (!force_ascii) { - cli->conn.smb1.client.capabilities |= CAP_UNICODE; + smb1_capabilities |= CAP_UNICODE; } if (use_spnego) { - cli->conn.smb1.client.capabilities |= CAP_EXTENDED_SECURITY; + smb1_capabilities |= CAP_EXTENDED_SECURITY; } if (use_level_II_oplocks) { - cli->conn.smb1.client.capabilities |= CAP_LEVEL_II_OPLOCKS; - } - - cli->conn.smb1.client.max_xmit = CLI_BUFFER_SIZE; - - cli->conn.smb1.capabilities = cli->conn.smb1.client.capabilities; - cli->conn.smb1.max_xmit = 1024; - - cli->conn.smb1.mid = 1; - - cli->conn.outgoing = tevent_queue_create(cli, "cli_outgoing"); - if (cli->conn.outgoing == NULL) { - goto error; - } - cli->conn.pending = NULL; - - cli->conn.remote_name = talloc_strdup(cli, remote_name); - if (cli->conn.remote_name == NULL) { - goto error; + smb1_capabilities |= CAP_LEVEL_II_OPLOCKS; } if (remote_realm) { - cli->conn.remote_realm = talloc_strdup(cli, remote_realm); - if (cli->conn.remote_realm == NULL) { + cli->remote_realm = talloc_strdup(cli, remote_realm); + if (cli->remote_realm == NULL) { goto error; } } - cli->conn.fd = fd; - - ss_length = sizeof(cli->conn.local_ss); - ret = getsockname(fd, - (struct sockaddr *)(void *)&cli->conn.local_ss, - &ss_length); - if (ret == -1) { - goto error; - } - ss_length = sizeof(cli->conn.remote_ss); - ret = getpeername(fd, - (struct sockaddr *)(void *)&cli->conn.remote_ss, - &ss_length); - if (ret == -1) { + cli->conn = smbXcli_conn_create(cli, fd, remote_name, + signing_state, + smb1_capabilities, + NULL); /* client_guid */ + if (cli->conn == NULL) { goto error; } @@ -369,7 +272,7 @@ struct cli_state *cli_state_create(TALLOC_CTX *mem_ctx, bool cli_state_encryption_on(struct cli_state *cli) { - return common_encryption_on(cli->trans_enc_state); + return smb1cli_conn_encryption_on(cli->conn); } @@ -411,12 +314,6 @@ static void _cli_shutdown(struct cli_state *cli) cli_state_disconnect(cli); - /* - * Need to free pending first, they remove themselves - */ - while (cli->conn.pending) { - talloc_free(cli->conn.pending[0]); - } TALLOC_FREE(cli); } @@ -452,27 +349,27 @@ void cli_shutdown(struct cli_state *cli) void cli_sockopt(struct cli_state *cli, const char *options) { - set_socket_options(cli->conn.fd, options); + smbXcli_conn_set_sockopt(cli->conn, options); } const struct sockaddr_storage *cli_state_local_sockaddr(struct cli_state *cli) { - return &cli->conn.local_ss; + return smbXcli_conn_local_sockaddr(cli->conn); } const struct sockaddr_storage *cli_state_remote_sockaddr(struct cli_state *cli) { - return &cli->conn.remote_ss; + return smbXcli_conn_remote_sockaddr(cli->conn); } const char *cli_state_remote_name(struct cli_state *cli) { - return cli->conn.remote_name; + return smbXcli_conn_remote_name(cli->conn); } const char *cli_state_remote_realm(struct cli_state *cli) { - return cli->conn.remote_realm; + return cli->remote_realm; } uint16_t cli_state_get_vc_num(struct cli_state *cli) @@ -482,7 +379,7 @@ uint16_t cli_state_get_vc_num(struct cli_state *cli) uint32_t cli_state_server_session_key(struct cli_state *cli) { - return cli->conn.smb1.server.session_key; + return smb1cli_conn_server_session_key(cli->conn); } /**************************************************************************** @@ -547,17 +444,17 @@ bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive) enum protocol_types cli_state_protocol(struct cli_state *cli) { - return cli->conn.protocol; + return smbXcli_conn_protocol(cli->conn); } uint32_t cli_state_capabilities(struct cli_state *cli) { - return cli->conn.smb1.capabilities; + return smb1cli_conn_capabilities(cli->conn); } uint32_t cli_state_available_size(struct cli_state *cli, uint32_t ofs) { - uint32_t ret = cli->conn.smb1.max_xmit; + uint32_t ret = smb1cli_conn_max_xmit(cli->conn); if (ofs >= ret) { return 0; @@ -570,32 +467,38 @@ uint32_t cli_state_available_size(struct cli_state *cli, uint32_t ofs) uint16_t cli_state_max_requests(struct cli_state *cli) { - return cli->conn.smb1.server.max_mux; + return smbXcli_conn_max_requests(cli->conn); } const uint8_t *cli_state_server_challenge(struct cli_state *cli) { - return cli->conn.smb1.server.challenge; + return smb1cli_conn_server_challenge(cli->conn); } const DATA_BLOB *cli_state_server_gss_blob(struct cli_state *cli) { - return &cli->conn.smb1.server.gss_blob; + return smbXcli_conn_server_gss_blob(cli->conn); } uint16_t cli_state_security_mode(struct cli_state *cli) { - return cli->conn.smb1.server.security_mode; + return smb1cli_conn_server_security_mode(cli->conn); } int cli_state_server_time_zone(struct cli_state *cli) { - return cli->conn.smb1.server.time_zone; + return smb1cli_conn_server_time_zone(cli->conn); } time_t cli_state_server_time(struct cli_state *cli) { - return cli->conn.smb1.server.system_time; + NTTIME nt; + time_t t; + + nt = smbXcli_conn_server_system_time(cli->conn); + t = nt_time_to_unix(nt); + + return t; } struct cli_echo_state { diff --git a/source3/libsmb/clierror.c b/source3/libsmb/clierror.c index 4ff5d9193b..4997d41fdf 100644 --- a/source3/libsmb/clierror.c +++ b/source3/libsmb/clierror.c @@ -21,6 +21,7 @@ #include "includes.h" #include "libsmb/libsmb.h" +#include "../libcli/smb/smbXcli_base.h" /*************************************************************************** Return an error message - either an NT error, SMB error or a RAP error. @@ -187,17 +188,14 @@ bool cli_state_is_connected(struct cli_state *cli) return false; } - if (cli->conn.fd == -1) { - return false; - } - - return true; + return smbXcli_conn_is_connected(cli->conn); } void cli_state_disconnect(struct cli_state *cli) { - if (cli->conn.fd != -1) { - close(cli->conn.fd); - } - cli->conn.fd = -1; + /* + * passing NT_STATUS_OK means the caller will not + * be notified, which matches the old behavior + */ + smbXcli_conn_disconnect(cli->conn, NT_STATUS_OK); } diff --git a/source3/libsmb/clifsinfo.c b/source3/libsmb/clifsinfo.c index a5b7838b2a..e0e42bded7 100644 --- a/source3/libsmb/clifsinfo.c +++ b/source3/libsmb/clifsinfo.c @@ -28,6 +28,7 @@ #include "trans2.h" #include "ntlmssp_wrap.h" #include "auth/gensec/gensec.h" +#include "../libcli/smb/smbXcli_base.h" /**************************************************************************** Get UNIX extensions version info. @@ -664,17 +665,14 @@ NTSTATUS cli_raw_ntlm_smb_encryption_start(struct cli_state *cli, data_blob_free(&blob_in); if (NT_STATUS_IS_OK(status)) { + es->enc_on = true; /* Replace the old state, if any. */ - if (cli->trans_enc_state) { - common_free_encryption_state(&cli->trans_enc_state); - } /* We only need the gensec_security part from here. * es is a malloc()ed pointer, so we cannot make * gensec_security a talloc child */ es->s.gensec_security = talloc_move(NULL, &auth_ntlmssp_state->gensec_security); - cli->trans_enc_state = es; - cli->trans_enc_state->enc_on = True; + smb1cli_conn_set_encryption(cli->conn, es); es = NULL; } @@ -837,12 +835,9 @@ NTSTATUS cli_gss_smb_encryption_start(struct cli_state *cli) data_blob_free(&blob_recv); if (NT_STATUS_IS_OK(status)) { + es->enc_on = true; /* Replace the old state, if any. */ - if (cli->trans_enc_state) { - common_free_encryption_state(&cli->trans_enc_state); - } - cli->trans_enc_state = es; - cli->trans_enc_state->enc_on = True; + smb1cli_conn_set_encryption(cli->conn, es); es = NULL; } diff --git a/source3/libsmb/clisigning.c b/source3/libsmb/clisigning.c index 2ce96c62fc..7dab9d3817 100644 --- a/source3/libsmb/clisigning.c +++ b/source3/libsmb/clisigning.c @@ -21,63 +21,25 @@ #include "includes.h" #include "libsmb/libsmb.h" -#include "../libcli/smb/smb_signing.h" +#include "../libcli/smb/smbXcli_base.h" bool cli_simple_set_signing(struct cli_state *cli, const DATA_BLOB user_session_key, const DATA_BLOB response) { - bool ok; - - ok = smb_signing_activate(cli->signing_state, - user_session_key, - response); - if (!ok) { - return false; - } - - return true; -} - -void cli_calculate_sign_mac(struct cli_state *cli, char *buf, uint32_t *seqnum) -{ - *seqnum = smb_signing_next_seqnum(cli->signing_state, false); - smb_signing_sign_pdu(cli->signing_state, (uint8_t *)buf, *seqnum); + return smb1cli_conn_activate_signing(cli->conn, + user_session_key, + response); } bool cli_check_sign_mac(struct cli_state *cli, const char *buf, uint32_t seqnum) { - bool ok; - - ok = smb_signing_check_pdu(cli->signing_state, - (const uint8_t *)buf, - seqnum); - - if (!ok) { - return false; - } - - return true; -} - -bool cli_set_signing_negotiated(struct cli_state *cli, - bool allowed, bool mandatory) -{ - return smb_signing_set_negotiated(cli->signing_state, - allowed, mandatory); + return smb1cli_conn_check_signing(cli->conn, + (const uint8_t *)buf, + seqnum); } bool client_is_signing_on(struct cli_state *cli) { - return smb_signing_is_active(cli->signing_state); -} - -bool client_is_signing_allowed(struct cli_state *cli) -{ - return smb_signing_is_allowed(cli->signing_state); -} - -bool client_is_signing_mandatory(struct cli_state *cli) -{ - return smb_signing_is_mandatory(cli->signing_state); + return smb1cli_conn_signing_is_active(cli->conn); } diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index e1f2c3e633..991deadfa5 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -853,13 +853,8 @@ NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli, bool cli_simple_set_signing(struct cli_state *cli, const DATA_BLOB user_session_key, const DATA_BLOB response); -void cli_calculate_sign_mac(struct cli_state *cli, char *buf, uint32_t *seqnum); bool cli_check_sign_mac(struct cli_state *cli, const char *buf, uint32_t seqnum); bool client_is_signing_on(struct cli_state *cli); -bool client_is_signing_allowed(struct cli_state *cli); -bool client_is_signing_mandatory(struct cli_state *cli); -bool cli_set_signing_negotiated(struct cli_state *cli, - bool allowed, bool mandatory); /* The following definitions come from libsmb/reparse_symlink.c */ diff --git a/source3/libsmb/smb2cli_base.h b/source3/libsmb/smb2cli_base.h index b6b4aba0a9..d68d65a304 100644 --- a/source3/libsmb/smb2cli_base.h +++ b/source3/libsmb/smb2cli_base.h @@ -37,20 +37,8 @@ static inline struct tevent_req *cli_state_smb2cli_req_send(TALLOC_CTX *mem_ctx, const uint8_t *dyn, uint32_t dyn_len) { - if (cli->smb2.conn == NULL) { - cli->smb2.conn = smbXcli_conn_create(cli, - cli->conn.fd, - cli->conn.remote_name, - SMB_SIGNING_OFF, - 0, /* smb1_capabilities */ - NULL); /* client guid */ - if (cli->smb2.conn == NULL) { - return NULL; - } - } - return smb2cli_req_send(mem_ctx, ev, - cli->smb2.conn, cmd, + cli->conn, cmd, additional_flags, clear_flags, timeout_msec, pid, tid, session, diff --git a/source3/libsmb/smb2cli_negprot.c b/source3/libsmb/smb2cli_negprot.c index ebf61ec980..0e3bcebeaa 100644 --- a/source3/libsmb/smb2cli_negprot.c +++ b/source3/libsmb/smb2cli_negprot.c @@ -24,19 +24,7 @@ NTSTATUS smb2cli_negprot(struct cli_state *cli) { - if (cli->smb2.conn == NULL) { - cli->smb2.conn = smbXcli_conn_create(cli, - cli->conn.fd, - cli->conn.remote_name, - 0, /* signing state */ - 0, /* smb1_capabilities */ - NULL); /* client guid */ - if (cli->smb2.conn == NULL) { - return NT_STATUS_NO_MEMORY; - } - } - - return smbXcli_negprot(cli->smb2.conn, cli->timeout, + return smbXcli_negprot(cli->conn, cli->timeout, PROTOCOL_SMB2_02, PROTOCOL_SMB2_02); } diff --git a/source3/libsmb/smb2cli_session.c b/source3/libsmb/smb2cli_session.c index 37420aa0da..85c536f5bc 100644 --- a/source3/libsmb/smb2cli_session.c +++ b/source3/libsmb/smb2cli_session.c @@ -305,13 +305,13 @@ struct tevent_req *smb2cli_sesssetup_ntlmssp_send(TALLOC_CTX *mem_ctx, blob_out = spnego_gen_negTokenInit(state, OIDs_ntlm, &blob_out, NULL); state->turn = 1; - state->cli->smb2.session = smbXcli_session_create(cli, cli->smb2.conn); + state->cli->smb2.session = smbXcli_session_create(cli, cli->conn); if (tevent_req_nomem(state->cli->smb2.session, req)) { return tevent_req_post(req, ev); } subreq = smb2cli_session_setup_send(state, state->ev, - state->cli->smb2.conn, + state->cli->conn, state->cli->timeout, state->cli->smb2.session, 0, /* in_flags */ @@ -392,7 +392,7 @@ static void smb2cli_sesssetup_ntlmssp_done(struct tevent_req *subreq) } subreq = smb2cli_session_setup_send(state, state->ev, - state->cli->smb2.conn, + state->cli->conn, state->cli->timeout, state->cli->smb2.session, 0, /* in_flags */ @@ -464,7 +464,7 @@ struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx, SSVAL(state->fixed, 0, 4); subreq = smb2cli_req_send(state, ev, - cli->smb2.conn, SMB2_OP_LOGOFF, + cli->conn, SMB2_OP_LOGOFF, 0, 0, /* flags */ cli->timeout, cli->smb2.pid, |