From e870cfec9f3512b0f1bd3110d7b975652525e28a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 14 Feb 2008 10:12:33 +1100 Subject: 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) --- source4/smb_server/smb/request.c | 61 ++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 25 deletions(-) (limited to 'source4/smb_server/smb/request.c') 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; -- cgit From 839ab724dc2d204bfbb0693aeed64f6f83a4266b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 14 Feb 2008 12:30:31 +1100 Subject: Fixed SMB2 rename operations from Vista clients We needed a flag in bufinfo to mark packets as SMB2, as it seems that SMB2 uses a different format for the RenameInformation buffer than SMB does Also handle the fact that SMB2 clients give the full path to the target file in the rename, not a relative path (This used to be commit 52d7972d95ddc19d22a4187b4d4428a6c3ed32d5) --- source4/smb_server/smb/request.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'source4/smb_server/smb/request.c') diff --git a/source4/smb_server/smb/request.c b/source4/smb_server/smb/request.c index 724055499b..d7f3793f23 100644 --- a/source4/smb_server/smb/request.c +++ b/source4/smb_server/smb/request.c @@ -37,7 +37,10 @@ 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.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; @@ -582,7 +585,7 @@ static size_t req_pull_ascii(struct request_bufinfo *bufinfo, const char **dest, 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) || bufinfo->unicode))) { + (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) { return req_pull_ucs2(bufinfo, dest, src, byte_len, flags); } -- cgit