diff options
30 files changed, 300 insertions, 180 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/interfaces.h b/source4/libcli/raw/interfaces.h index ce6323f2e5..16db17d7ab 100644 --- a/source4/libcli/raw/interfaces.h +++ b/source4/libcli/raw/interfaces.h @@ -1000,7 +1000,7 @@ union smb_setfileinfo { struct { union smb_handle_or_path file; uint8_t overwrite; - uint32_t root_fid; + uint64_t root_fid; const char *new_name; } in; } rename_information; 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..355d092583 100644 --- a/source4/libcli/raw/rawrequest.c +++ b/source4/libcli/raw/rawrequest.c @@ -34,6 +34,20 @@ /* 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.flags = 0; + if (req->flags2 & FLAGS2_UNICODE_STRINGS) { + req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE; + } + 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 +312,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 +561,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 +575,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 +614,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 +657,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->flags & BUFINFO_FLAG_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 +675,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 +694,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 +711,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..2a572e58ee 100644 --- a/source4/libcli/raw/request.h +++ b/source4/libcli/raw/request.h @@ -22,11 +22,25 @@ #include "libcli/raw/signing.h" +#define BUFINFO_FLAG_UNICODE 0x0001 +#define BUFINFO_FLAG_SMB2 0x0002 + +/* + buffer limit structure used by both SMB and SMB2 + */ +struct request_bufinfo { + TALLOC_CTX *mem_ctx; + uint32_t flags; + 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 +70,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..35229dc45f 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.flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2; + 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/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index 340913cd4d..ce977873c8 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -63,6 +63,10 @@ static uint32_t pvfs_setfileinfo_access(union smb_setfileinfo *info) } break; + case RAW_SFILEINFO_RENAME_INFORMATION: + needed = SEC_STD_DELETE; + break; + default: needed = SEC_FILE_WRITE_ATTRIBUTE; break; @@ -84,7 +88,8 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, char *new_name, *p; /* renames are only allowed within a directory */ - if (strchr_m(info->rename_information.in.new_name, '\\')) { + if (strchr_m(info->rename_information.in.new_name, '\\') && + (req->ctx->protocol != PROTOCOL_SMB2)) { return NT_STATUS_NOT_SUPPORTED; } @@ -98,24 +103,32 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, return NT_STATUS_INVALID_PARAMETER; } - /* w2k3 does not appear to allow relative rename */ - if (info->rename_information.in.root_fid != 0) { + /* w2k3 does not appear to allow relative rename. On SMB2, vista sends it sometimes, + but I suspect it is just uninitialised memory */ + if (info->rename_information.in.root_fid != 0 && + (req->ctx->protocol != PROTOCOL_SMB2)) { return NT_STATUS_INVALID_PARAMETER; } /* construct the fully qualified windows name for the new file name */ - new_name = talloc_strdup(req, name->original_name); - if (new_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - p = strrchr_m(new_name, '\\'); - if (p == NULL) { - return NT_STATUS_OBJECT_NAME_INVALID; - } - *p = 0; + if (req->ctx->protocol == PROTOCOL_SMB2) { + /* SMB2 sends the full path of the new name */ + new_name = talloc_asprintf(req, "\\%s", info->rename_information.in.new_name); + } else { + new_name = talloc_strdup(req, name->original_name); + if (new_name == NULL) { + return NT_STATUS_NO_MEMORY; + } + p = strrchr_m(new_name, '\\'); + if (p == NULL) { + return NT_STATUS_OBJECT_NAME_INVALID; + } else { + *p = 0; + } - new_name = talloc_asprintf(req, "%s\\%s", new_name, - info->rename_information.in.new_name); + new_name = talloc_asprintf(req, "%s\\%s", new_name, + info->rename_information.in.new_name); + } if (new_name == NULL) { return NT_STATUS_NO_MEMORY; } diff --git a/source4/smb_server/blob.c b/source4/smb_server/blob.c index 2b870118ba..795e7ce585 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,9 +521,9 @@ 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; + uint32_t len, ofs; DATA_BLOB str_blob; switch (level) { @@ -560,21 +560,26 @@ 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); - - st->rename_information.in.overwrite = CVAL(blob->data, 0); - st->rename_information.in.root_fid = IVAL(blob->data, 4); - 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, + if (bufinfo->flags & BUFINFO_FLAG_SMB2) { + /* SMB2 uses a different format for rename information */ + BLOB_CHECK_MIN_SIZE(blob, 20); + st->rename_information.in.overwrite = CVAL(blob->data, 0); + st->rename_information.in.root_fid = BVAL(blob->data, 4); + len = IVAL(blob->data,16); + ofs = 20; + } else { + BLOB_CHECK_MIN_SIZE(blob, 12); + st->rename_information.in.overwrite = CVAL(blob->data, 0); + st->rename_information.in.root_fid = IVAL(blob->data, 4); + len = IVAL(blob->data, 8); + ofs = 12; + } + str_blob = *blob; + str_blob.length = MIN(str_blob.length, ofs+len); + smbsrv_blob_pull_string(bufinfo, &str_blob, ofs, &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..d7f3793f23 100644 --- a/source4/smb_server/smb/request.c +++ b/source4/smb_server/smb/request.c @@ -33,6 +33,20 @@ /* 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.flags = 0; + if (req->flags2 & FLAGS2_UNICODE_STRINGS) { + req->in.bufinfo.flags |= BUFINFO_FLAG_UNICODE; + } + 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 +475,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 +492,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 +505,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 +533,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 +542,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 +558,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 +582,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->flags & BUFINFO_FLAG_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 +602,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 +617,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 +631,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..dea7c9e79e 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.flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2; + 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}; |