diff options
author | Andrew Tridgell <tridge@samba.org> | 2008-02-14 10:12:33 +1100 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2008-02-14 10:12:33 +1100 |
commit | e870cfec9f3512b0f1bd3110d7b975652525e28a (patch) | |
tree | 2a26a6764bcbc5bd63a8402b6ac1fd7e68be6724 | |
parent | 4c01d70a4469ffc25f9a10473cb135bb38a454c7 (diff) | |
download | samba-e870cfec9f3512b0f1bd3110d7b975652525e28a.tar.gz samba-e870cfec9f3512b0f1bd3110d7b975652525e28a.tar.bz2 samba-e870cfec9f3512b0f1bd3110d7b975652525e28a.zip |
Convert SMB and SMB2 code to use a common buffer handling structure
This converts our SMB and SMB2 code to use a common structure "struct
request_bufinfo" for information on the buffer bounds of a packet,
alignment information and string handling. This allows us to use a
common backend for SMB and SMB2 code, while still using all the same
string and blob handling functions.
Up to now we had been passing a NULL req handle into these common
routines from the SMB2 side of the server, which meant that we failed
any operation which did a bounds checked string extraction (such as a
RenameInformation setinfo call, which is what Vista uses for renaming
files)
There is still some more work to be done on this - for example we can
now remove many of the SMB2 specific buffer handling functions that we
had, and use the SMB ones.
(This used to be commit ca6d9be6cb6a403a81b18fa6e9a6a0518d7f0f68)
28 files changed, 246 insertions, 157 deletions
diff --git a/source4/libcli/raw/clisession.c b/source4/libcli/raw/clisession.c index 617131c53c..55cb3ef305 100644 --- a/source4/libcli/raw/clisession.c +++ b/source4/libcli/raw/clisession.c @@ -177,9 +177,9 @@ NTSTATUS smb_raw_sesssetup_recv(struct smbcli_request *req, parms->old.out.action = SVAL(req->in.vwv, VWV(2)); p = req->in.data; if (p) { - p += smbcli_req_pull_string(req, mem_ctx, &parms->old.out.os, p, -1, STR_TERMINATE); - p += smbcli_req_pull_string(req, mem_ctx, &parms->old.out.lanman, p, -1, STR_TERMINATE); - p += smbcli_req_pull_string(req, mem_ctx, &parms->old.out.domain, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.os, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.lanman, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->old.out.domain, p, -1, STR_TERMINATE); } break; @@ -190,10 +190,10 @@ NTSTATUS smb_raw_sesssetup_recv(struct smbcli_request *req, parms->nt1.out.action = SVAL(req->in.vwv, VWV(2)); p = req->in.data; if (p) { - p += smbcli_req_pull_string(req, mem_ctx, &parms->nt1.out.os, p, -1, STR_TERMINATE); - p += smbcli_req_pull_string(req, mem_ctx, &parms->nt1.out.lanman, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.os, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.lanman, p, -1, STR_TERMINATE); if (p < (req->in.data + req->in.data_size)) { - p += smbcli_req_pull_string(req, mem_ctx, &parms->nt1.out.domain, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->nt1.out.domain, p, -1, STR_TERMINATE); } } break; @@ -209,11 +209,11 @@ NTSTATUS smb_raw_sesssetup_recv(struct smbcli_request *req, break; } - parms->spnego.out.secblob = smbcli_req_pull_blob(req, mem_ctx, p, len); + parms->spnego.out.secblob = smbcli_req_pull_blob(&req->in.bufinfo, mem_ctx, p, len); p += parms->spnego.out.secblob.length; - p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE); - p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE); - p += smbcli_req_pull_string(req, mem_ctx, &parms->spnego.out.workgroup, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.os, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.lanman, p, -1, STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->spnego.out.workgroup, p, -1, STR_TERMINATE); break; case RAW_SESSSETUP_SMB2: diff --git a/source4/libcli/raw/clitransport.c b/source4/libcli/raw/clitransport.c index 62c32d3058..288f0612de 100644 --- a/source4/libcli/raw/clitransport.c +++ b/source4/libcli/raw/clitransport.c @@ -444,6 +444,8 @@ static NTSTATUS smbcli_transport_finish_recv(void *private, DATA_BLOB blob) req->in.ptr = req->in.data; req->flags2 = SVAL(req->in.hdr, HDR_FLG2); + smb_setup_bufinfo(req); + if (!(req->flags2 & FLAGS2_32_BIT_ERROR_CODES)) { int class = CVAL(req->in.hdr,HDR_RCLS); int code = SVAL(req->in.hdr,HDR_ERR); @@ -637,7 +639,7 @@ NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size); NT_STATUS_HAVE_NO_MEMORY(p->out.data); - if (!smbcli_raw_pull_data(req, req->in.data, p->out.size, p->out.data)) { + if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } diff --git a/source4/libcli/raw/clitree.c b/source4/libcli/raw/clitree.c index 35f3335322..507bde999a 100644 --- a/source4/libcli/raw/clitree.c +++ b/source4/libcli/raw/clitree.c @@ -123,9 +123,9 @@ NTSTATUS smb_raw_tcon_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, p = req->in.data; if (!p) break; - p += smbcli_req_pull_string(req, mem_ctx, &parms->tconx.out.dev_type, - p, -1, STR_ASCII | STR_TERMINATE); - p += smbcli_req_pull_string(req, mem_ctx, &parms->tconx.out.fs_type, + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->tconx.out.dev_type, + p, -1, STR_ASCII | STR_TERMINATE); + p += smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->tconx.out.fs_type, p, -1, STR_TERMINATE); break; diff --git a/source4/libcli/raw/libcliraw.h b/source4/libcli/raw/libcliraw.h index 0032eb4e94..7111649fc1 100644 --- a/source4/libcli/raw/libcliraw.h +++ b/source4/libcli/raw/libcliraw.h @@ -250,8 +250,8 @@ struct smbcli_request { /* the mid of this packet - used to match replies */ uint16_t mid; - struct request_buffer in; - struct request_buffer out; + struct smb_request_buffer in; + struct smb_request_buffer out; /* information on what to do with a reply when it is received asyncronously. If this is not setup when a reply is received then diff --git a/source4/libcli/raw/rawfile.c b/source4/libcli/raw/rawfile.c index 3b6ca68526..d9383401b7 100644 --- a/source4/libcli/raw/rawfile.c +++ b/source4/libcli/raw/rawfile.c @@ -616,7 +616,7 @@ NTSTATUS smb_raw_open_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, unio case RAW_OPEN_CTEMP: SMBCLI_CHECK_WCT(req, 1); parms->ctemp.out.file.fnum = SVAL(req->in.vwv, VWV(0)); - smbcli_req_pull_string(req, mem_ctx, &parms->ctemp.out.name, req->in.data, -1, STR_TERMINATE | STR_ASCII); + smbcli_req_pull_string(&req->in.bufinfo, mem_ctx, &parms->ctemp.out.name, req->in.data, -1, STR_TERMINATE | STR_ASCII); break; case RAW_OPEN_SPLOPEN: @@ -675,7 +675,7 @@ NTSTATUS smb_raw_open_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, unio parms->openxreadx.out.nread = SVAL(req->in.vwv, VWV(5)); if (parms->openxreadx.out.nread > MAX(parms->openxreadx.in.mincnt, parms->openxreadx.in.maxcnt) || - !smbcli_raw_pull_data(req, req->in.hdr + SVAL(req->in.vwv, VWV(6)), + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)), parms->openxreadx.out.nread, parms->openxreadx.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; diff --git a/source4/libcli/raw/rawioctl.c b/source4/libcli/raw/rawioctl.c index 9205f84e86..957e554c6b 100644 --- a/source4/libcli/raw/rawioctl.c +++ b/source4/libcli/raw/rawioctl.c @@ -59,7 +59,7 @@ static NTSTATUS smb_raw_smbioctl_recv(struct smbcli_request *req, return smbcli_request_destroy(req); } - parms->ioctl.out.blob = smbcli_req_pull_blob(req, mem_ctx, req->in.data, -1); + parms->ioctl.out.blob = smbcli_req_pull_blob(&req->in.bufinfo, mem_ctx, req->in.data, -1); return smbcli_request_destroy(req); } diff --git a/source4/libcli/raw/rawnegotiate.c b/source4/libcli/raw/rawnegotiate.c index 1f5e34779b..ec2ada53ff 100644 --- a/source4/libcli/raw/rawnegotiate.c +++ b/source4/libcli/raw/rawnegotiate.c @@ -135,14 +135,14 @@ NTSTATUS smb_raw_negotiate_recv(struct smbcli_request *req) if (req->in.data_size < 16) { goto failed; } - transport->negotiate.server_guid = smbcli_req_pull_blob(req, transport, req->in.data, 16); - transport->negotiate.secblob = smbcli_req_pull_blob(req, transport, req->in.data + 16, req->in.data_size - 16); + transport->negotiate.server_guid = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data, 16); + transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data + 16, req->in.data_size - 16); } else { if (req->in.data_size < (transport->negotiate.key_len)) { goto failed; } - transport->negotiate.secblob = smbcli_req_pull_blob(req, transport, req->in.data, transport->negotiate.key_len); - smbcli_req_pull_string(req, transport, &transport->negotiate.server_domain, + transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data, transport->negotiate.key_len); + smbcli_req_pull_string(&req->in.bufinfo, transport, &transport->negotiate.server_domain, req->in.data+transport->negotiate.key_len, req->in.data_size-transport->negotiate.key_len, STR_UNICODE|STR_NOALIGN); /* here comes the server name */ @@ -168,7 +168,7 @@ NTSTATUS smb_raw_negotiate_recv(struct smbcli_request *req) if ((SVAL(req->in.vwv,VWV(5)) & 0x2)) { transport->negotiate.writebraw_supported = 1; } - transport->negotiate.secblob = smbcli_req_pull_blob(req, transport, + transport->negotiate.secblob = smbcli_req_pull_blob(&req->in.bufinfo, transport, req->in.data, req->in.data_size); } else { /* the old core protocol */ diff --git a/source4/libcli/raw/rawreadwrite.c b/source4/libcli/raw/rawreadwrite.c index b0c49ddab7..2005e36e04 100644 --- a/source4/libcli/raw/rawreadwrite.c +++ b/source4/libcli/raw/rawreadwrite.c @@ -137,7 +137,7 @@ NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms) SMBCLI_CHECK_WCT(req, 5); parms->lockread.out.nread = SVAL(req->in.vwv, VWV(0)); if (parms->lockread.out.nread > parms->lockread.in.count || - !smbcli_raw_pull_data(req, req->in.data+3, + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.data+3, parms->lockread.out.nread, parms->lockread.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } @@ -148,7 +148,7 @@ NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms) SMBCLI_CHECK_WCT(req, 5); parms->read.out.nread = SVAL(req->in.vwv, VWV(0)); if (parms->read.out.nread > parms->read.in.count || - !smbcli_raw_pull_data(req, req->in.data+3, + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.data+3, parms->read.out.nread, parms->read.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; } @@ -175,7 +175,7 @@ NTSTATUS smb_raw_read_recv(struct smbcli_request *req, union smb_read *parms) } if (parms->readx.out.nread > MAX(parms->readx.in.mincnt, parms->readx.in.maxcnt) || - !smbcli_raw_pull_data(req, req->in.hdr + SVAL(req->in.vwv, VWV(6)), + !smbcli_raw_pull_data(&req->in.bufinfo, req->in.hdr + SVAL(req->in.vwv, VWV(6)), parms->readx.out.nread, parms->readx.out.data)) { req->status = NT_STATUS_BUFFER_TOO_SMALL; diff --git a/source4/libcli/raw/rawrequest.c b/source4/libcli/raw/rawrequest.c index 3551e5d441..dd60cc7f62 100644 --- a/source4/libcli/raw/rawrequest.c +++ b/source4/libcli/raw/rawrequest.c @@ -34,6 +34,17 @@ /* assume that a character will not consume more than 3 bytes per char */ #define MAX_BYTES_PER_CHAR 3 +/* setup the bufinfo used for strings and range checking */ +void smb_setup_bufinfo(struct smbcli_request *req) +{ + req->in.bufinfo.mem_ctx = req; + req->in.bufinfo.unicode = (req->flags2 & FLAGS2_UNICODE_STRINGS)?true:false; + req->in.bufinfo.align_base = req->in.buffer; + req->in.bufinfo.data = req->in.data; + req->in.bufinfo.data_size = req->in.data_size; +} + + /* destroy a request structure and return final status */ NTSTATUS smbcli_request_destroy(struct smbcli_request *req) { @@ -298,6 +309,9 @@ NTSTATUS smbcli_chained_advance(struct smbcli_request *req) req->in.data = req->in.vwv + 2 + req->in.wct * 2; req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct)); + /* fix the bufinfo */ + smb_setup_bufinfo(req); + if (buffer + 3 + req->in.wct*2 + req->in.data_size > req->in.buffer + req->in.size) { return NT_STATUS_BUFFER_TOO_SMALL; @@ -544,13 +558,13 @@ size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *by on failure zero is returned and *dest is set to NULL, otherwise the number of bytes consumed in the packet is returned */ -static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_ctx, +static size_t smbcli_req_pull_ucs2(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, char **dest, const uint8_t *src, int byte_len, uint_t flags) { int src_len, src_len2, alignment=0; ssize_t ret; - if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) { + if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) { src++; alignment=1; if (byte_len != -1) { @@ -558,7 +572,7 @@ static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_c } } - src_len = req->in.data_size - PTR_DIFF(src, req->in.data); + src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); if (src_len < 0) { *dest = NULL; return 0; @@ -597,13 +611,13 @@ static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_c on failure zero is returned and *dest is set to NULL, otherwise the number of bytes consumed in the packet is returned */ -size_t smbcli_req_pull_ascii(struct smbcli_request *req, TALLOC_CTX *mem_ctx, +size_t smbcli_req_pull_ascii(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, char **dest, const uint8_t *src, int byte_len, uint_t flags) { int src_len, src_len2; ssize_t ret; - src_len = req->in.data_size - PTR_DIFF(src, req->in.data); + src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); if (src_len < 0) { *dest = NULL; return 0; @@ -640,15 +654,15 @@ size_t smbcli_req_pull_ascii(struct smbcli_request *req, TALLOC_CTX *mem_ctx, on failure zero is returned and *dest is set to NULL, otherwise the number of bytes consumed in the packet is returned */ -size_t smbcli_req_pull_string(struct smbcli_request *req, TALLOC_CTX *mem_ctx, +size_t smbcli_req_pull_string(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, char **dest, const uint8_t *src, int byte_len, uint_t flags) { if (!(flags & STR_ASCII) && - (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) { - return smbcli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags); + (((flags & STR_UNICODE) || bufinfo->unicode))) { + return smbcli_req_pull_ucs2(bufinfo, mem_ctx, dest, src, byte_len, flags); } - return smbcli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags); + return smbcli_req_pull_ascii(bufinfo, mem_ctx, dest, src, byte_len, flags); } @@ -658,11 +672,11 @@ size_t smbcli_req_pull_string(struct smbcli_request *req, TALLOC_CTX *mem_ctx, if byte_len is -1 then limit the blob only by packet size */ -DATA_BLOB smbcli_req_pull_blob(struct smbcli_request *req, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len) +DATA_BLOB smbcli_req_pull_blob(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len) { int src_len; - src_len = req->in.data_size - PTR_DIFF(src, req->in.data); + src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); if (src_len < 0) { return data_blob(NULL, 0); @@ -677,13 +691,13 @@ DATA_BLOB smbcli_req_pull_blob(struct smbcli_request *req, TALLOC_CTX *mem_ctx, /* check that a lump of data in a request is within the bounds of the data section of the packet */ -static bool smbcli_req_data_oob(struct smbcli_request *req, const uint8_t *ptr, uint32_t count) +static bool smbcli_req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count) { /* be careful with wraparound! */ - if (ptr < req->in.data || - ptr >= req->in.data + req->in.data_size || - count > req->in.data_size || - ptr + count > req->in.data + req->in.data_size) { + if (ptr < bufinfo->data || + ptr >= bufinfo->data + bufinfo->data_size || + count > bufinfo->data_size || + ptr + count > bufinfo->data + bufinfo->data_size) { return true; } return false; @@ -694,11 +708,11 @@ static bool smbcli_req_data_oob(struct smbcli_request *req, const uint8_t *ptr, return false if any part is outside the data portion of the packet */ -bool smbcli_raw_pull_data(struct smbcli_request *req, const uint8_t *src, int len, uint8_t *dest) +bool smbcli_raw_pull_data(struct request_bufinfo *bufinfo, const uint8_t *src, int len, uint8_t *dest) { if (len == 0) return true; - if (smbcli_req_data_oob(req, src, len)) { + if (smbcli_req_data_oob(bufinfo, src, len)) { return false; } diff --git a/source4/libcli/raw/rawsearch.c b/source4/libcli/raw/rawsearch.c index 33fa90d68d..fb2b09467c 100644 --- a/source4/libcli/raw/rawsearch.c +++ b/source4/libcli/raw/rawsearch.c @@ -54,7 +54,7 @@ static void smb_raw_search_backend(struct smbcli_request *req, search_data.search.write_time = raw_pull_dos_date(req->transport, p + 22); search_data.search.size = IVAL(p, 26); - smbcli_req_pull_ascii(req, mem_ctx, &name, p+30, 13, STR_ASCII); + smbcli_req_pull_ascii(&req->in.bufinfo, mem_ctx, &name, p+30, 13, STR_ASCII); search_data.search.name = name; if (!callback(private, &search_data)) { break; diff --git a/source4/libcli/raw/request.h b/source4/libcli/raw/request.h index 803a450e3c..6776d3c349 100644 --- a/source4/libcli/raw/request.h +++ b/source4/libcli/raw/request.h @@ -23,10 +23,21 @@ #include "libcli/raw/signing.h" /* + buffer limit structure used by both SMB and SMB2 + */ +struct request_bufinfo { + TALLOC_CTX *mem_ctx; + bool unicode; + const uint8_t *align_base; + const uint8_t *data; + size_t data_size; +}; + +/* Shared state structure between client and server, representing the basic packet. */ -struct request_buffer { +struct smb_request_buffer { /* the raw SMB buffer, including the 4 byte length header */ uint8_t *buffer; @@ -56,6 +67,9 @@ struct request_buffer { * a send packet is done we need to move this * pointer */ uint8_t *ptr; + + /* this is used to range check and align strings and buffers */ + struct request_bufinfo bufinfo; }; #endif diff --git a/source4/libcli/raw/smb_signing.c b/source4/libcli/raw/smb_signing.c index 0053710aaf..4acfb9d16d 100644 --- a/source4/libcli/raw/smb_signing.c +++ b/source4/libcli/raw/smb_signing.c @@ -65,7 +65,7 @@ static bool smbcli_set_smb_signing_common(struct smbcli_transport *transport) return true; } -void mark_packet_signed(struct request_buffer *out) +void mark_packet_signed(struct smb_request_buffer *out) { uint16_t flags2; flags2 = SVAL(out->hdr, HDR_FLG2); @@ -101,7 +101,7 @@ bool signing_good(struct smb_signing_context *sign_info, return true; } -void sign_outgoing_message(struct request_buffer *out, DATA_BLOB *mac_key, unsigned int seq_num) +void sign_outgoing_message(struct smb_request_buffer *out, DATA_BLOB *mac_key, unsigned int seq_num) { uint8_t calc_md5_mac[16]; struct MD5Context md5_ctx; @@ -133,7 +133,7 @@ void sign_outgoing_message(struct request_buffer *out, DATA_BLOB *mac_key, unsig Uncomment this to test if the remote server actually verifies signitures...*/ } -bool check_signed_incoming_message(struct request_buffer *in, DATA_BLOB *mac_key, uint_t seq_num) +bool check_signed_incoming_message(struct smb_request_buffer *in, DATA_BLOB *mac_key, uint_t seq_num) { bool good; uint8_t calc_md5_mac[16]; diff --git a/source4/libcli/smb2/request.c b/source4/libcli/smb2/request.c index 46ec24145f..0b680fb166 100644 --- a/source4/libcli/smb2/request.c +++ b/source4/libcli/smb2/request.c @@ -28,6 +28,21 @@ #include "libcli/smb2/smb2_calls.h" #include "param/param.h" +/* fill in the bufinfo */ +void smb2_setup_bufinfo(struct smb2_request *req) +{ + req->in.bufinfo.mem_ctx = req; + req->in.bufinfo.unicode = true; + req->in.bufinfo.align_base = req->in.buffer; + if (req->in.dynamic) { + req->in.bufinfo.data = req->in.dynamic; + req->in.bufinfo.data_size = req->in.body_size - req->in.body_fixed; + } else { + req->in.bufinfo.data = NULL; + req->in.bufinfo.data_size = 0; + } +} + /* initialise a smb2 request */ diff --git a/source4/libcli/smb2/smb2.h b/source4/libcli/smb2/smb2.h index db13ab69b3..af08b0180a 100644 --- a/source4/libcli/smb2/smb2.h +++ b/source4/libcli/smb2/smb2.h @@ -19,6 +19,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "libcli/raw/request.h" + struct smb2_options { uint32_t timeout; }; @@ -102,6 +104,9 @@ struct smb2_request_buffer { * this will be moved when some dynamic data is pushed */ uint8_t *dynamic; + + /* this is used to range check and align strings and buffers */ + struct request_bufinfo bufinfo; }; diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c index dceb78382a..1d601fdbfe 100644 --- a/source4/libcli/smb2/transport.c +++ b/source4/libcli/smb2/transport.c @@ -216,6 +216,8 @@ static NTSTATUS smb2_transport_finish_recv(void *private, DATA_BLOB blob) } } + smb2_setup_bufinfo(req); + DEBUG(2, ("SMB2 RECV seqnum=0x%llx\n", (long long)req->seqnum)); dump_data(5, req->in.body, req->in.body_size); diff --git a/source4/smb_server/blob.c b/source4/smb_server/blob.c index 2b870118ba..caf6fb447d 100644 --- a/source4/smb_server/blob.c +++ b/source4/smb_server/blob.c @@ -78,7 +78,7 @@ NTSTATUS smbsrv_blob_fill_data(TALLOC_CTX *mem_ctx, /* pull a string from a blob in a trans2 request */ -size_t smbsrv_blob_pull_string(struct smbsrv_request *req, +size_t smbsrv_blob_pull_string(struct request_bufinfo *bufinfo, const DATA_BLOB *blob, uint16_t offset, const char **str, @@ -92,7 +92,7 @@ size_t smbsrv_blob_pull_string(struct smbsrv_request *req, return 0; } - return req_pull_string(req, str, + return req_pull_string(bufinfo, str, blob->data + offset, blob->length - offset, STR_NO_RANGE_CHECK | flags); @@ -521,7 +521,7 @@ NTSTATUS smbsrv_pull_passthru_sfileinfo(TALLOC_CTX *mem_ctx, union smb_setfileinfo *st, const DATA_BLOB *blob, int default_str_flags, - struct smbsrv_request *req) + struct request_bufinfo *bufinfo) { uint32_t len; DATA_BLOB str_blob; @@ -560,12 +560,8 @@ NTSTATUS smbsrv_pull_passthru_sfileinfo(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; case RAW_SFILEINFO_RENAME_INFORMATION: - if (!req) { - /* - * TODO: get rid of smbsrv_request argument of - * smbsrv_blob_pull_string() - */ - return NT_STATUS_NOT_IMPLEMENTED; + if (!bufinfo) { + return NT_STATUS_INTERNAL_ERROR; } BLOB_CHECK_MIN_SIZE(blob, 12); @@ -574,7 +570,7 @@ NTSTATUS smbsrv_pull_passthru_sfileinfo(TALLOC_CTX *mem_ctx, len = IVAL(blob->data, 8); str_blob.data = blob->data+12; str_blob.length = MIN(blob->length, len); - smbsrv_blob_pull_string(req, &str_blob, 0, + smbsrv_blob_pull_string(bufinfo, &str_blob, 0, &st->rename_information.in.new_name, STR_UNICODE); if (st->rename_information.in.new_name == NULL) { diff --git a/source4/smb_server/smb/negprot.c b/source4/smb_server/smb/negprot.c index b57e5e1d64..00ff3862f5 100644 --- a/source4/smb_server/smb/negprot.c +++ b/source4/smb_server/smb/negprot.c @@ -509,7 +509,7 @@ void smbsrv_reply_negprot(struct smbsrv_request *req) return; } protos[protos_count] = NULL; - len = req_pull_ascii4(req, (const char **)&protos[protos_count], p, STR_ASCII|STR_TERMINATE); + len = req_pull_ascii4(&req->in.bufinfo, (const char **)&protos[protos_count], p, STR_ASCII|STR_TERMINATE); p += len; if (len == 0 || !protos[protos_count]) break; diff --git a/source4/smb_server/smb/nttrans.c b/source4/smb_server/smb/nttrans.c index dd2ec15e39..f6edc407d6 100644 --- a/source4/smb_server/smb/nttrans.c +++ b/source4/smb_server/smb/nttrans.c @@ -134,7 +134,7 @@ static NTSTATUS nttrans_create(struct smbsrv_request *req, io->ntcreatex.in.sec_desc = NULL; io->ntcreatex.in.ea_list = NULL; - req_pull_string(req, &io->ntcreatex.in.fname, + req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname, params + 53, MIN(fname_len+1, trans->in.params.length - 53), STR_NO_RANGE_CHECK | STR_TERMINATE); @@ -622,8 +622,8 @@ void smbsrv_reply_nttrans(struct smbsrv_request *req) memcpy(trans->in.setup, (char *)(req->in.vwv) + VWV(19), sizeof(uint16_t) * trans->in.setup_count); - if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) || - !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) { + if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) || + !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } diff --git a/source4/smb_server/smb/receive.c b/source4/smb_server/smb/receive.c index 3f590decca..e3d247cbc0 100644 --- a/source4/smb_server/smb/receive.c +++ b/source4/smb_server/smb/receive.c @@ -151,6 +151,9 @@ NTSTATUS smbsrv_recv_smb_request(void *private, DATA_BLOB blob) req->flags2 = SVAL(req->in.hdr, HDR_FLG2); + /* fix the bufinfo */ + smbsrv_setup_bufinfo(req); + if (!smbsrv_signing_check_incoming(req)) { smbsrv_send_error(req, NT_STATUS_ACCESS_DENIED); return NT_STATUS_OK; @@ -620,6 +623,9 @@ void smbsrv_chain_reply(struct smbsrv_request *req) req->in.data_size = data_size; req->in.ptr = data; + /* fix the bufinfo */ + smbsrv_setup_bufinfo(req); + req->chain_count++; SSVAL(req->out.vwv, VWV(0), chain_cmd); diff --git a/source4/smb_server/smb/reply.c b/source4/smb_server/smb/reply.c index aff0587bc6..40cad91062 100644 --- a/source4/smb_server/smb/reply.c +++ b/source4/smb_server/smb/reply.c @@ -58,9 +58,9 @@ void smbsrv_reply_tcon(struct smbsrv_request *req) con.tcon.level = RAW_TCON_TCON; p = req->in.data; - p += req_pull_ascii4(req, &con.tcon.in.service, p, STR_TERMINATE); - p += req_pull_ascii4(req, &con.tcon.in.password, p, STR_TERMINATE); - p += req_pull_ascii4(req, &con.tcon.in.dev, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.service, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.password, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &con.tcon.in.dev, p, STR_TERMINATE); if (!con.tcon.in.service || !con.tcon.in.password || !con.tcon.in.dev) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); @@ -106,14 +106,14 @@ void smbsrv_reply_tcon_and_X(struct smbsrv_request *req) p = req->in.data; - if (!req_pull_blob(req, p, passlen, &con.tconx.in.password)) { + if (!req_pull_blob(&req->in.bufinfo, p, passlen, &con.tconx.in.password)) { smbsrv_send_error(req, NT_STATUS_ILL_FORMED_PASSWORD); return; } p += passlen; - p += req_pull_string(req, &con.tconx.in.path, p, -1, STR_TERMINATE); - p += req_pull_string(req, &con.tconx.in.device, p, -1, STR_ASCII); + p += req_pull_string(&req->in.bufinfo, &con.tconx.in.path, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &con.tconx.in.device, p, -1, STR_ASCII); if (!con.tconx.in.path || !con.tconx.in.device) { smbsrv_send_error(req, NT_STATUS_BAD_DEVICE_TYPE); @@ -223,7 +223,7 @@ void smbsrv_reply_chkpth(struct smbsrv_request *req) SMBSRV_TALLOC_IO_PTR(io, union smb_chkpath); SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC); - req_pull_ascii4(req, &io->chkpath.in.path, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &io->chkpath.in.path, req->in.data, STR_TERMINATE); SMBSRV_CALL_NTVFS_BACKEND(ntvfs_chkpath(req->ntvfs, io)); } @@ -264,7 +264,7 @@ void smbsrv_reply_getatr(struct smbsrv_request *req) st->getattr.level = RAW_FILEINFO_GETATTR; /* parse request */ - req_pull_ascii4(req, &st->getattr.in.file.path, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &st->getattr.in.file.path, req->in.data, STR_TERMINATE); if (!st->getattr.in.file.path) { smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); return; @@ -290,7 +290,7 @@ void smbsrv_reply_setatr(struct smbsrv_request *req) st->setattr.in.attrib = SVAL(req->in.vwv, VWV(0)); st->setattr.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1)); - req_pull_ascii4(req, &st->setattr.in.file.path, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &st->setattr.in.file.path, req->in.data, STR_TERMINATE); if (!st->setattr.in.file.path) { smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); @@ -379,7 +379,7 @@ void smbsrv_reply_open(struct smbsrv_request *req) oi->openold.in.open_mode = SVAL(req->in.vwv, VWV(0)); oi->openold.in.search_attrs = SVAL(req->in.vwv, VWV(1)); - req_pull_ascii4(req, &oi->openold.in.fname, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &oi->openold.in.fname, req->in.data, STR_TERMINATE); if (!oi->openold.in.fname) { smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); @@ -452,7 +452,7 @@ void smbsrv_reply_open_and_X(struct smbsrv_request *req) oi->openx.in.size = IVAL(req->in.vwv, VWV(9)); oi->openx.in.timeout = IVAL(req->in.vwv, VWV(11)); - req_pull_ascii4(req, &oi->openx.in.fname, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &oi->openx.in.fname, req->in.data, STR_TERMINATE); if (!oi->openx.in.fname) { smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); @@ -502,7 +502,7 @@ void smbsrv_reply_mknew(struct smbsrv_request *req) oi->mknew.in.attrib = SVAL(req->in.vwv, VWV(0)); oi->mknew.in.write_time = srv_pull_dos_date3(req->smb_conn, req->in.vwv + VWV(1)); - req_pull_ascii4(req, &oi->mknew.in.fname, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &oi->mknew.in.fname, req->in.data, STR_TERMINATE); if (!oi->mknew.in.fname) { smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); @@ -551,7 +551,7 @@ void smbsrv_reply_ctemp(struct smbsrv_request *req) /* the filename is actually a directory name, the server provides a filename in that directory */ - req_pull_ascii4(req, &oi->ctemp.in.directory, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &oi->ctemp.in.directory, req->in.data, STR_TERMINATE); if (!oi->ctemp.in.directory) { smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); @@ -576,7 +576,7 @@ void smbsrv_reply_unlink(struct smbsrv_request *req) unl->unlink.in.attrib = SVAL(req->in.vwv, VWV(0)); - req_pull_ascii4(req, &unl->unlink.in.pattern, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &unl->unlink.in.pattern, req->in.data, STR_TERMINATE); SMBSRV_CALL_NTVFS_BACKEND(ntvfs_unlink(req->ntvfs, unl)); } @@ -958,7 +958,7 @@ void smbsrv_reply_write(struct smbsrv_request *req) io->write.in.data = req->in.data + 3; /* make sure they gave us the data they promised */ - if (req_data_oob(req, io->write.in.data, io->write.in.count)) { + if (req_data_oob(&req->in.bufinfo, io->write.in.data, io->write.in.count)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } @@ -1027,7 +1027,7 @@ void smbsrv_reply_write_and_X(struct smbsrv_request *req) } /* make sure the data is in bounds */ - if (req_data_oob(req, io->writex.in.data, io->writex.in.count)) { + if (req_data_oob(&req->in.bufinfo, io->writex.in.data, io->writex.in.count)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } @@ -1163,7 +1163,7 @@ void smbsrv_reply_writeclose(struct smbsrv_request *req) io->writeclose.in.data = req->in.data + 1; /* make sure they gave us the data they promised */ - if (req_data_oob(req, io->writeclose.in.data, io->writeclose.in.count)) { + if (req_data_oob(&req->in.bufinfo, io->writeclose.in.data, io->writeclose.in.count)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } @@ -1313,7 +1313,7 @@ void smbsrv_reply_printopen(struct smbsrv_request *req) oi->splopen.in.setup_length = SVAL(req->in.vwv, VWV(0)); oi->splopen.in.mode = SVAL(req->in.vwv, VWV(1)); - req_pull_ascii4(req, &oi->splopen.in.ident, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &oi->splopen.in.ident, req->in.data, STR_TERMINATE); SMBSRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, oi)); } @@ -1426,7 +1426,7 @@ void smbsrv_reply_printwrite(struct smbsrv_request *req) io->splwrite.in.data = req->in.data + 3; /* make sure they gave us the data they promised */ - if (req_data_oob(req, io->splwrite.in.data, io->splwrite.in.count)) { + if (req_data_oob(&req->in.bufinfo, io->splwrite.in.data, io->splwrite.in.count)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } @@ -1449,7 +1449,7 @@ void smbsrv_reply_mkdir(struct smbsrv_request *req) SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC); io->generic.level = RAW_MKDIR_MKDIR; - req_pull_ascii4(req, &io->mkdir.in.path, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &io->mkdir.in.path, req->in.data, STR_TERMINATE); SMBSRV_CALL_NTVFS_BACKEND(ntvfs_mkdir(req->ntvfs, io)); } @@ -1467,7 +1467,7 @@ void smbsrv_reply_rmdir(struct smbsrv_request *req) SMBSRV_TALLOC_IO_PTR(io, struct smb_rmdir); SMBSRV_SETUP_NTVFS_REQUEST(reply_simple_send, NTVFS_ASYNC_STATE_MAY_ASYNC); - req_pull_ascii4(req, &io->in.path, req->in.data, STR_TERMINATE); + req_pull_ascii4(&req->in.bufinfo, &io->in.path, req->in.data, STR_TERMINATE); SMBSRV_CALL_NTVFS_BACKEND(ntvfs_rmdir(req->ntvfs, io)); } @@ -1490,8 +1490,8 @@ void smbsrv_reply_mv(struct smbsrv_request *req) io->rename.in.attrib = SVAL(req->in.vwv, VWV(0)); p = req->in.data; - p += req_pull_ascii4(req, &io->rename.in.pattern1, p, STR_TERMINATE); - p += req_pull_ascii4(req, &io->rename.in.pattern2, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern1, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &io->rename.in.pattern2, p, STR_TERMINATE); if (!io->rename.in.pattern1 || !io->rename.in.pattern2) { smbsrv_send_error(req, NT_STATUS_FOOBAR); @@ -1521,8 +1521,8 @@ void smbsrv_reply_ntrename(struct smbsrv_request *req) io->ntrename.in.cluster_size = IVAL(req->in.vwv, VWV(2)); p = req->in.data; - p += req_pull_ascii4(req, &io->ntrename.in.old_name, p, STR_TERMINATE); - p += req_pull_ascii4(req, &io->ntrename.in.new_name, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.old_name, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &io->ntrename.in.new_name, p, STR_TERMINATE); if (!io->ntrename.in.old_name || !io->ntrename.in.new_name) { smbsrv_send_error(req, NT_STATUS_FOOBAR); @@ -1568,8 +1568,8 @@ void smbsrv_reply_copy(struct smbsrv_request *req) cp->in.flags = SVAL(req->in.vwv, VWV(2)); p = req->in.data; - p += req_pull_ascii4(req, &cp->in.path1, p, STR_TERMINATE); - p += req_pull_ascii4(req, &cp->in.path2, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path1, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &cp->in.path2, p, STR_TERMINATE); if (!cp->in.path1 || !cp->in.path2) { smbsrv_send_error(req, NT_STATUS_FOOBAR); @@ -1638,7 +1638,7 @@ void smbsrv_reply_lockingX(struct smbsrv_request *req) } /* make sure we got the promised data */ - if (req_data_oob(req, req->in.data, total_locks * lck_size)) { + if (req_data_oob(&req->in.bufinfo, req->in.data, total_locks * lck_size)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } @@ -1877,22 +1877,22 @@ static void reply_sesssetup_old(struct smbsrv_request *req) passlen = SVAL(req->in.vwv, VWV(7)); /* check the request isn't malformed */ - if (req_data_oob(req, req->in.data, passlen)) { + if (req_data_oob(&req->in.bufinfo, req->in.data, passlen)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } p = req->in.data; - if (!req_pull_blob(req, p, passlen, &io->old.in.password)) { + if (!req_pull_blob(&req->in.bufinfo, p, passlen, &io->old.in.password)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } p += passlen; - p += req_pull_string(req, &io->old.in.user, p, -1, STR_TERMINATE); - p += req_pull_string(req, &io->old.in.domain, p, -1, STR_TERMINATE); - p += req_pull_string(req, &io->old.in.os, p, -1, STR_TERMINATE); - p += req_pull_string(req, &io->old.in.lanman, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->old.in.user, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->old.in.domain, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->old.in.os, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->old.in.lanman, p, -1, STR_TERMINATE); /* call the generic handler */ smbsrv_sesssetup_backend(req, io); @@ -1921,28 +1921,28 @@ static void reply_sesssetup_nt1(struct smbsrv_request *req) io->nt1.in.capabilities = IVAL(req->in.vwv, VWV(11)); /* check the request isn't malformed */ - if (req_data_oob(req, req->in.data, passlen1) || - req_data_oob(req, req->in.data + passlen1, passlen2)) { + if (req_data_oob(&req->in.bufinfo, req->in.data, passlen1) || + req_data_oob(&req->in.bufinfo, req->in.data + passlen1, passlen2)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } p = req->in.data; - if (!req_pull_blob(req, p, passlen1, &io->nt1.in.password1)) { + if (!req_pull_blob(&req->in.bufinfo, p, passlen1, &io->nt1.in.password1)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } p += passlen1; - if (!req_pull_blob(req, p, passlen2, &io->nt1.in.password2)) { + if (!req_pull_blob(&req->in.bufinfo, p, passlen2, &io->nt1.in.password2)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } p += passlen2; - p += req_pull_string(req, &io->nt1.in.user, p, -1, STR_TERMINATE); - p += req_pull_string(req, &io->nt1.in.domain, p, -1, STR_TERMINATE); - p += req_pull_string(req, &io->nt1.in.os, p, -1, STR_TERMINATE); - p += req_pull_string(req, &io->nt1.in.lanman, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->nt1.in.user, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->nt1.in.domain, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->nt1.in.os, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->nt1.in.lanman, p, -1, STR_TERMINATE); /* call the generic handler */ smbsrv_sesssetup_backend(req, io); @@ -1971,15 +1971,15 @@ static void reply_sesssetup_spnego(struct smbsrv_request *req) io->spnego.in.capabilities = IVAL(req->in.vwv, VWV(10)); p = req->in.data; - if (!req_pull_blob(req, p, blob_len, &io->spnego.in.secblob)) { + if (!req_pull_blob(&req->in.bufinfo, p, blob_len, &io->spnego.in.secblob)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } p += blob_len; - p += req_pull_string(req, &io->spnego.in.os, p, -1, STR_TERMINATE); - p += req_pull_string(req, &io->spnego.in.lanman, p, -1, STR_TERMINATE); - p += req_pull_string(req, &io->spnego.in.workgroup, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->spnego.in.os, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->spnego.in.lanman, p, -1, STR_TERMINATE); + p += req_pull_string(&req->in.bufinfo, &io->spnego.in.workgroup, p, -1, STR_TERMINATE); /* call the generic handler */ smbsrv_sesssetup_backend(req, io); @@ -2199,7 +2199,7 @@ void smbsrv_reply_ntcreate_and_X(struct smbsrv_request *req) fname_len++; } - req_pull_string(req, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE); + req_pull_string(&req->in.bufinfo, &io->ntcreatex.in.fname, req->in.data, fname_len, STR_TERMINATE); if (!io->ntcreatex.in.fname) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; diff --git a/source4/smb_server/smb/request.c b/source4/smb_server/smb/request.c index 8f6d664500..724055499b 100644 --- a/source4/smb_server/smb/request.c +++ b/source4/smb_server/smb/request.c @@ -33,6 +33,17 @@ /* we over allocate the data buffer to prevent too many realloc calls */ #define REQ_OVER_ALLOCATION 0 +/* setup the bufinfo used for strings and range checking */ +void smbsrv_setup_bufinfo(struct smbsrv_request *req) +{ + req->in.bufinfo.mem_ctx = req; + req->in.bufinfo.unicode = (req->flags2 & FLAGS2_UNICODE_STRINGS)?true:false; + req->in.bufinfo.align_base = req->in.buffer; + req->in.bufinfo.data = req->in.data; + req->in.bufinfo.data_size = req->in.data_size; +} + + static int smbsrv_request_destructor(struct smbsrv_request *req) { DLIST_REMOVE(req->smb_conn->requests, req); @@ -461,13 +472,13 @@ size_t req_append_var_block(struct smbsrv_request *req, on failure zero is returned and *dest is set to NULL, otherwise the number of bytes consumed in the packet is returned */ -static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags) +static size_t req_pull_ucs2(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags) { int src_len, src_len2, alignment=0; ssize_t ret; char *dest2; - if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) { + if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) { src++; alignment=1; if (byte_len != -1) { @@ -478,7 +489,7 @@ static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const if (flags & STR_NO_RANGE_CHECK) { src_len = byte_len; } else { - src_len = req->in.data_size - PTR_DIFF(src, req->in.data); + src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); if (byte_len != -1 && src_len > byte_len) { src_len = byte_len; } @@ -491,11 +502,11 @@ static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const src_len2 = utf16_len_n(src, src_len); if (src_len2 == 0) { - *dest = talloc_strdup(req, ""); + *dest = talloc_strdup(bufinfo->mem_ctx, ""); return src_len2 + alignment; } - ret = convert_string_talloc(req, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2); + ret = convert_string_talloc(bufinfo->mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2); if (ret == -1) { *dest = NULL; @@ -519,7 +530,7 @@ static size_t req_pull_ucs2(struct smbsrv_request *req, const char **dest, const on failure zero is returned and *dest is set to NULL, otherwise the number of bytes consumed in the packet is returned */ -static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags) +static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags) { int src_len, src_len2; ssize_t ret; @@ -528,7 +539,7 @@ static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, cons if (flags & STR_NO_RANGE_CHECK) { src_len = byte_len; } else { - src_len = req->in.data_size - PTR_DIFF(src, req->in.data); + src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data); if (src_len < 0) { *dest = NULL; return 0; @@ -544,7 +555,7 @@ static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, cons src_len2++; } - ret = convert_string_talloc(req, lp_iconv_convenience(global_loadparm), CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2); + ret = convert_string_talloc(bufinfo->mem_ctx, lp_iconv_convenience(global_loadparm), CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2); if (ret == -1) { *dest = NULL; @@ -568,14 +579,14 @@ static size_t req_pull_ascii(struct smbsrv_request *req, const char **dest, cons on failure zero is returned and *dest is set to NULL, otherwise the number of bytes consumed in the packet is returned */ -size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint8_t *src, int byte_len, uint_t flags) +size_t req_pull_string(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, int byte_len, uint_t flags) { if (!(flags & STR_ASCII) && - (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) { - return req_pull_ucs2(req, dest, src, byte_len, flags); + (((flags & STR_UNICODE) || bufinfo->unicode))) { + return req_pull_ucs2(bufinfo, dest, src, byte_len, flags); } - return req_pull_ascii(req, dest, src, byte_len, flags); + return req_pull_ascii(bufinfo, dest, src, byte_len, flags); } @@ -588,13 +599,13 @@ size_t req_pull_string(struct smbsrv_request *req, const char **dest, const uint on failure *dest is set to the zero length string. This seems to match win2000 behaviour */ -size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint8_t *src, uint_t flags) +size_t req_pull_ascii4(struct request_bufinfo *bufinfo, const char **dest, const uint8_t *src, uint_t flags) { ssize_t ret; - if (PTR_DIFF(src, req->in.data) + 1 > req->in.data_size) { + if (PTR_DIFF(src, bufinfo->data) + 1 > bufinfo->data_size) { /* win2000 treats this as the empty string! */ - (*dest) = talloc_strdup(req, ""); + (*dest) = talloc_strdup(bufinfo->mem_ctx, ""); return 0; } @@ -603,9 +614,9 @@ size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint behaviour */ src++; - ret = req_pull_string(req, dest, src, -1, flags); + ret = req_pull_string(bufinfo, dest, src, -1, flags); if (ret == -1) { - (*dest) = talloc_strdup(req, ""); + (*dest) = talloc_strdup(bufinfo->mem_ctx, ""); return 1; } @@ -617,30 +628,30 @@ size_t req_pull_ascii4(struct smbsrv_request *req, const char **dest, const uint return false if any part is outside the data portion of the packet */ -bool req_pull_blob(struct smbsrv_request *req, const uint8_t *src, int len, DATA_BLOB *blob) +bool req_pull_blob(struct request_bufinfo *bufinfo, const uint8_t *src, int len, DATA_BLOB *blob) { - if (len != 0 && req_data_oob(req, src, len)) { + if (len != 0 && req_data_oob(bufinfo, src, len)) { return false; } - (*blob) = data_blob_talloc(req, src, len); + (*blob) = data_blob_talloc(bufinfo->mem_ctx, src, len); return true; } /* check that a lump of data in a request is within the bounds of the data section of the packet */ -bool req_data_oob(struct smbsrv_request *req, const uint8_t *ptr, uint32_t count) +bool req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count) { if (count == 0) { return false; } /* be careful with wraparound! */ - if (ptr < req->in.data || - ptr >= req->in.data + req->in.data_size || - count > req->in.data_size || - ptr + count > req->in.data + req->in.data_size) { + if (ptr < bufinfo->data || + ptr >= bufinfo->data + bufinfo->data_size || + count > bufinfo->data_size || + ptr + count > bufinfo->data + bufinfo->data_size) { return true; } return false; diff --git a/source4/smb_server/smb/search.c b/source4/smb_server/smb/search.c index ccf2ff7365..90b2331271 100644 --- a/source4/smb_server/smb/search.c +++ b/source4/smb_server/smb/search.c @@ -129,14 +129,14 @@ void smbsrv_reply_search(struct smbsrv_request *req) SMBSRV_TALLOC_IO_PTR(sf, union smb_search_first); p = req->in.data; - p += req_pull_ascii4(req, &sf->search_first.in.pattern, + p += req_pull_ascii4(&req->in.bufinfo, &sf->search_first.in.pattern, p, STR_TERMINATE); if (!sf->search_first.in.pattern) { smbsrv_send_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND); return; } - if (req_data_oob(req, p, 3)) { + if (req_data_oob(&req->in.bufinfo, p, 3)) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } @@ -167,7 +167,7 @@ void smbsrv_reply_search(struct smbsrv_request *req) union smb_search_next *sn; if (resume_key_length != 21 || - req_data_oob(req, p, 21) || + req_data_oob(&req->in.bufinfo, p, 21) || level == RAW_SEARCH_FUNIQUE) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; @@ -242,13 +242,13 @@ void smbsrv_reply_fclose(struct smbsrv_request *req) SMBSRV_SETUP_NTVFS_REQUEST(reply_fclose_send, NTVFS_ASYNC_STATE_MAY_ASYNC); p = req->in.data; - p += req_pull_ascii4(req, &pattern, p, STR_TERMINATE); + p += req_pull_ascii4(&req->in.bufinfo, &pattern, p, STR_TERMINATE); if (pattern && *pattern) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } - if (req_data_oob(req, p, 3)) { + if (req_data_oob(&req->in.bufinfo, p, 3)) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } @@ -264,7 +264,7 @@ void smbsrv_reply_fclose(struct smbsrv_request *req) return; } - if (req_data_oob(req, p, 21)) { + if (req_data_oob(&req->in.bufinfo, p, 21)) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } diff --git a/source4/smb_server/smb/trans2.c b/source4/smb_server/smb/trans2.c index 45ea234d09..3336169bb0 100644 --- a/source4/smb_server/smb/trans2.c +++ b/source4/smb_server/smb/trans2.c @@ -248,7 +248,7 @@ static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op) io->t2open.in.num_eas = 0; io->t2open.in.eas = NULL; - smbsrv_blob_pull_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0); + smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 28, &io->t2open.in.fname, 0); if (io->t2open.in.fname == NULL) { return NT_STATUS_FOOBAR; } @@ -296,7 +296,7 @@ static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op) NT_STATUS_HAVE_NO_MEMORY(io); io->t2mkdir.level = RAW_MKDIR_T2MKDIR; - smbsrv_blob_pull_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0); + smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4, &io->t2mkdir.in.path, 0); if (io->t2mkdir.in.path == NULL) { return NT_STATUS_FOOBAR; } @@ -461,7 +461,7 @@ static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op level = SVAL(trans->in.params.data, 0); - smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0); + smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0); if (st->generic.in.file.path == NULL) { return NT_STATUS_FOOBAR; } @@ -602,7 +602,7 @@ static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req, return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st, blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req), - req); + &req->in.bufinfo); } /* @@ -661,7 +661,7 @@ static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op * level = SVAL(trans->in.params.data, 0); - smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0); + smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0); if (st->generic.in.file.path == NULL) { return NT_STATUS_FOOBAR; } @@ -859,7 +859,7 @@ static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op level = SVAL(trans->in.params.data, 6); search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8); - smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0); + smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0); if (search->t2ffirst.in.pattern == NULL) { return NT_STATUS_FOOBAR; } @@ -945,7 +945,7 @@ static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op) search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6); search->t2fnext.in.flags = SVAL(trans->in.params.data, 10); - smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0); + smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0); if (search->t2fnext.in.last_name == NULL) { return NT_STATUS_FOOBAR; } @@ -1240,11 +1240,11 @@ static void reply_trans_generic(struct smbsrv_request *req, uint8_t command) } if (command == SMBtrans) { - req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE); + req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE); } - if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans->in.params) || - !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans->in.data)) { + if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) || + !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) { smbsrv_send_error(req, NT_STATUS_FOOBAR); return; } @@ -1302,8 +1302,8 @@ static void reply_transs_generic(struct smbsrv_request *req, uint8_t command) data_ofs = SVAL(req->in.vwv, VWV(6)); data_disp = SVAL(req->in.vwv, VWV(7)); - if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, ¶ms) || - !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) { + if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, ¶ms) || + !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) { smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER); return; } diff --git a/source4/smb_server/smb2/fileinfo.c b/source4/smb_server/smb2/fileinfo.c index 00c455e351..e375b7308f 100644 --- a/source4/smb_server/smb2/fileinfo.c +++ b/source4/smb_server/smb2/fileinfo.c @@ -268,7 +268,7 @@ static NTSTATUS smb2srv_setinfo_file(struct smb2srv_setinfo_op *op, uint8_t smb2 status = smbsrv_pull_passthru_sfileinfo(io, io->generic.level, io, &op->info->in.blob, - STR_UNICODE, NULL); + STR_UNICODE, &op->req->in.bufinfo); NT_STATUS_NOT_OK_RETURN(status); return ntvfs_setfileinfo(op->req->ntvfs, io); diff --git a/source4/smb_server/smb2/negprot.c b/source4/smb_server/smb2/negprot.c index 7c295c05ab..578eadbe8f 100644 --- a/source4/smb_server/smb2/negprot.c +++ b/source4/smb_server/smb2/negprot.c @@ -238,6 +238,8 @@ void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req) req->in.body_size = body_fixed_size; req->in.dynamic = NULL; + smb2srv_setup_bufinfo(req); + SIVAL(req->in.hdr, 0, SMB2_MAGIC); SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); SSVAL(req->in.hdr, SMB2_HDR_EPOCH, 0); diff --git a/source4/smb_server/smb2/receive.c b/source4/smb_server/smb2/receive.c index 393b3f0cc5..58070065fc 100644 --- a/source4/smb_server/smb2/receive.c +++ b/source4/smb_server/smb2/receive.c @@ -30,6 +30,22 @@ #include "ntvfs/ntvfs.h" #include "param/param.h" + +/* fill in the bufinfo */ +void smb2srv_setup_bufinfo(struct smb2srv_request *req) +{ + req->in.bufinfo.mem_ctx = req; + req->in.bufinfo.unicode = true; + req->in.bufinfo.align_base = req->in.buffer; + if (req->in.dynamic) { + req->in.bufinfo.data = req->in.dynamic; + req->in.bufinfo.data_size = req->in.body_size - req->in.body_fixed; + } else { + req->in.bufinfo.data = NULL; + req->in.bufinfo.data_size = 0; + } +} + static int smb2srv_request_destructor(struct smb2srv_request *req) { DLIST_REMOVE(req->smb_conn->requests2.list, req); @@ -180,6 +196,8 @@ static void smb2srv_chain_reply(struct smb2srv_request *p_req) } } + smb2srv_setup_bufinfo(req); + if (p_req->chained_file_handle) { memcpy(req->_chained_file_handle, p_req->_chained_file_handle, @@ -430,6 +448,8 @@ NTSTATUS smbsrv_recv_smb2_request(void *private, DATA_BLOB blob) } } + smb2srv_setup_bufinfo(req); + /* * TODO: - make sure the length field is 64 * - make sure it's a request diff --git a/source4/smb_server/smb2/tcon.c b/source4/smb_server/smb2/tcon.c index b375ce6b4b..50094b806d 100644 --- a/source4/smb_server/smb2/tcon.c +++ b/source4/smb_server/smb2/tcon.c @@ -55,6 +55,8 @@ static NTSTATUS smb2srv_send_oplock_break(void *p, struct ntvfs_handle *h, uint8 req->seqnum = UINT64_MAX; + smb2srv_setup_bufinfo(req); + SIVAL(req->in.hdr, 0, SMB2_MAGIC); SSVAL(req->in.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); SSVAL(req->in.hdr, SMB2_HDR_EPOCH, 0); diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h index bb0673b7d0..776fe1b71b 100644 --- a/source4/smb_server/smb_server.h +++ b/source4/smb_server/smb_server.h @@ -254,8 +254,8 @@ struct smbsrv_request { /* the sequence number for signing */ uint64_t seq_num; - struct request_buffer in; - struct request_buffer out; + struct smb_request_buffer in; + struct smb_request_buffer out; }; enum security_types {SEC_SHARE,SEC_USER}; |