summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2011-11-16 11:20:15 +0100
committerStefan Metzmacher <metze@samba.org>2011-11-24 19:02:30 +0100
commit7c5651c3f63b29e689c9e07a33bec751a5e49ac7 (patch)
tree5a0bfb5f2d5756a1c21dc7ce745c2b2e3dc2129b
parent94cb738dd4deab7dc97e0da77a406264297713b9 (diff)
downloadsamba-7c5651c3f63b29e689c9e07a33bec751a5e49ac7.tar.gz
samba-7c5651c3f63b29e689c9e07a33bec751a5e49ac7.tar.xz
samba-7c5651c3f63b29e689c9e07a33bec751a5e49ac7.zip
smbXcli: add smb1cli_inbuf_parse_chain()
metze
-rw-r--r--libcli/smb/smbXcli_base.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c
index ce6e3242e97..d53be9b6f2f 100644
--- a/libcli/smb/smbXcli_base.c
+++ b/libcli/smb/smbXcli_base.c
@@ -1164,6 +1164,180 @@ static void smbXcli_conn_received(struct tevent_req *subreq)
}
}
+static NTSTATUS smb1cli_inbuf_parse_chain(uint8_t *buf, TALLOC_CTX *mem_ctx,
+ struct iovec **piov, int *pnum_iov)
+{
+ struct iovec *iov;
+ int num_iov;
+ size_t buflen;
+ size_t taken;
+ size_t remaining;
+ uint8_t *hdr;
+ uint8_t cmd;
+ uint32_t wct_ofs;
+
+ buflen = smb_len_nbt(buf);
+ taken = 0;
+
+ hdr = buf + NBT_HDR_SIZE;
+
+ if (buflen < MIN_SMB_SIZE) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * This returns iovec elements in the following order:
+ *
+ * - SMB header
+ *
+ * - Parameter Block
+ * - Data Block
+ *
+ * - Parameter Block
+ * - Data Block
+ *
+ * - Parameter Block
+ * - Data Block
+ */
+ num_iov = 1;
+
+ iov = talloc_array(mem_ctx, struct iovec, num_iov);
+ if (iov == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov[0].iov_base = hdr;
+ iov[0].iov_len = HDR_WCT;
+ taken += HDR_WCT;
+
+ cmd = CVAL(hdr, HDR_COM);
+ wct_ofs = HDR_WCT;
+
+ while (true) {
+ size_t len = buflen - taken;
+ struct iovec *cur;
+ struct iovec *iov_tmp;
+ uint8_t wct;
+ uint32_t bcc_ofs;
+ uint16_t bcc;
+ size_t needed;
+
+ /*
+ * we need at least WCT and BCC
+ */
+ needed = sizeof(uint8_t) + sizeof(uint16_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * Now we check if the specified words are there
+ */
+ wct = CVAL(hdr, wct_ofs);
+ needed += wct * sizeof(uint16_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * Now we check if the specified bytes are there
+ */
+ bcc_ofs = wct_ofs + sizeof(uint8_t) + wct * sizeof(uint16_t);
+ bcc = SVAL(hdr, bcc_ofs);
+ needed += bcc * sizeof(uint8_t);
+ if (len < needed) {
+ DEBUG(10, ("%s: %d bytes left, expected at least %d\n",
+ __location__, (int)len, (int)needed));
+ goto inval;
+ }
+
+ /*
+ * we allocate 2 iovec structures for words and bytes
+ */
+ iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
+ num_iov + 2);
+ if (iov_tmp == NULL) {
+ TALLOC_FREE(iov);
+ return NT_STATUS_NO_MEMORY;
+ }
+ iov = iov_tmp;
+ cur = &iov[num_iov];
+ num_iov += 2;
+
+ cur[0].iov_len = wct * sizeof(uint16_t);
+ cur[0].iov_base = hdr + (wct_ofs + sizeof(uint8_t));
+ cur[1].iov_len = bcc * sizeof(uint8_t);
+ cur[1].iov_base = hdr + (bcc_ofs + sizeof(uint16_t));
+
+ taken += needed;
+
+ if (!smb1cli_is_andx_req(cmd)) {
+ /*
+ * If the current command does not have AndX chanining
+ * we are done.
+ */
+ break;
+ }
+
+ if (wct == 0 && bcc == 0) {
+ /*
+ * An empty response also ends the chain,
+ * most likely with an error.
+ */
+ break;
+ }
+
+ if (wct < 2) {
+ DEBUG(10, ("%s: wct[%d] < 2 for cmd[0x%02X]\n",
+ __location__, (int)wct, (int)cmd));
+ goto inval;
+ }
+ cmd = CVAL(cur[0].iov_base, 0);
+ if (cmd == 0xFF) {
+ /*
+ * If it is the end of the chain we are also done.
+ */
+ break;
+ }
+ wct_ofs = SVAL(cur[0].iov_base, 2);
+
+ if (wct_ofs < taken) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (wct_ofs > buflen) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ /*
+ * we consumed everything up to the start of the next
+ * parameter block.
+ */
+ taken = wct_ofs;
+ }
+
+ remaining = buflen - taken;
+
+ if (remaining > 0 && num_iov >= 3) {
+ /*
+ * The last DATA block gets the remaining
+ * bytes, this is needed to support
+ * CAP_LARGE_WRITEX and CAP_LARGE_READX.
+ */
+ iov[num_iov-1].iov_len += remaining;
+ }
+
+ *piov = iov;
+ *pnum_iov = num_iov;
+ return NT_STATUS_OK;
+
+inval:
+ TALLOC_FREE(iov);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+}
+
static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
TALLOC_CTX *tmp_mem,
uint8_t *inbuf)