From 41b97ab70653fe390d389eafe91388a0e3df56b5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 15:50:47 -0700 Subject: [PATCH 01/10] Add ea_list_has_invalid_name() function. Invalid character list probed from Windows Server 2012. Bug 9992: Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/include/proto.h | 2 ++ source3/lib/filename_util.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/source3/include/proto.h b/source3/include/proto.h index 189b286..e553c72 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1955,6 +1955,8 @@ NTSTATUS copy_smb_filename(TALLOC_CTX *ctx, struct smb_filename **smb_fname_out); bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname); bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname); +bool is_invalid_windows_ea_name(const char *name); +bool ea_list_has_invalid_name(struct ea_list *ea_list); /* The following definitions come from lib/dummyroot.c */ diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index e22a97a..54cc2bd 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -204,3 +204,37 @@ bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) return StrCaseCmp(smb_fname->stream_name, "::$DATA") == 0; } + +/**************************************************************************** + Filter out Windows invalid EA names (list probed from Windows 2012). +****************************************************************************/ + +static char bad_ea_name_chars[] = "\"*+,/:;<=>?[\\]|"; + +bool is_invalid_windows_ea_name(const char *name) +{ + int i; + /* EA name is pulled as ascii so we can examine + individual bytes here. */ + for (i = 0; name[i] != 0; i++) { + int val = (name[i] & 0xff); + if (val < ' ' || strchr(bad_ea_name_chars, val)) { + return true; + } + } + return false; +} + +bool ea_list_has_invalid_name(struct ea_list *ea_list) +{ + if (lp_posix_pathnames()) { + return false; + } + + for (;ea_list; ea_list = ea_list->next) { + if (is_invalid_windows_ea_name(ea_list->ea.name)) { + return true; + } + } + return false; +} -- 1.8.3 From 8dd3ab52a798f92ceb623d7541aea77dffcc25fb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 15:52:47 -0700 Subject: [PATCH 02/10] Ensure set_ea cannot set invalid Windows EA names. Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/smbd/trans2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 01b0130..83d20c4 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -558,6 +558,15 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, return NT_STATUS_ACCESS_DENIED; } + /* + * Filter out invalid Windows EA names - before + * we set *any* of them. + */ + + if (ea_list_has_invalid_name(ea_list)) { + return STATUS_INVALID_EA_NAME; + } + /* For now setting EAs on streams isn't supported. */ fname = smb_fname->base_name; -- 1.8.3 From 3c48e7078d241111d76f94b23513481398fe2b0b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 16:21:18 -0700 Subject: [PATCH 03/10] Ensure we never return an EA name to a Windows client it can't handle. Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/smbd/trans2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 83d20c4..af64cd2 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -317,6 +317,15 @@ static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_str || samba_private_attr_name(names[i])) continue; + /* + * Filter out any underlying POSIX EA names + * that a Windows client can't handle. + */ + if (!lp_posix_pathnames() && + is_invalid_windows_ea_name(names[i])) { + continue; + } + listp = TALLOC_P(mem_ctx, struct ea_list); if (listp == NULL) { return NULL; -- 1.8.3 From d35a213c791b60c186599b6d00ab2e7bbf1497c4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 16:02:50 -0700 Subject: [PATCH 04/10] Ensure we can't create a file using SMB2_CREATE with an invalid EA list. Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/smbd/smb2_create.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 5b81099..bec85de 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -550,6 +550,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } + + if (ea_list_has_invalid_name(ea_list)) { + tevent_req_nterror(req, STATUS_INVALID_EA_NAME); + return tevent_req_post(req, ev); + } } if (mxac) { -- 1.8.3 From 6aa4ed6a071a234f4fd0697f8e91d706f2f73937 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 10 Jul 2013 12:38:41 -0700 Subject: [PATCH 05/10] Add the ability to send an NTSTATUS result back with a trans2 reply so we can return a parameter block with an error code. This is needed when returning a STATUS_INVALID_NAME result (tested from Windows 2012). Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/smbd/blocking.c | 2 +- source3/smbd/proto.h | 1 + source3/smbd/trans2.c | 43 ++++++++++++++++++++++++++++++------------- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 07fdfa0..9d4d4f4 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -552,7 +552,7 @@ static bool process_trans2(struct blocking_lock_record *blr) SSVAL(params,0,0); /* Fake up max_data_bytes here - we know it fits. */ - send_trans2_replies(blr->fsp->conn, blr->req, params, 2, NULL, 0, 0xffff); + send_trans2_replies(blr->fsp->conn, blr->req, NT_STATUS_OK, params, 2, NULL, 0, 0xffff); return True; } diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index b4c5cb4..d0bc969 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1083,6 +1083,7 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used); void send_trans2_replies(connection_struct *conn, struct smb_request *req, + NTSTATUS status, const char *params, int paramsize, const char *pdata, diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index af64cd2..a87d67f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -832,6 +832,7 @@ static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list * void send_trans2_replies(connection_struct *conn, struct smb_request *req, + NTSTATUS status, const char *params, int paramsize, const char *pdata, @@ -872,6 +873,14 @@ void send_trans2_replies(connection_struct *conn, if(params_to_send == 0 && data_to_send == 0) { reply_outbuf(req, 10, 0); + if (NT_STATUS_V(status)) { + uint8_t eclass; + uint32_t ecode; + ntstatus_to_dos(status, &eclass, &ecode); + error_packet_set((char *)req->outbuf, + eclass, ecode, status, + __LINE__,__FILE__); + } show_msg((char *)req->outbuf); if (!srv_send_smb(sconn, (char *)req->outbuf, @@ -1002,6 +1011,13 @@ void send_trans2_replies(connection_struct *conn, ERRDOS,ERRbufferoverflow, STATUS_BUFFER_OVERFLOW, __LINE__,__FILE__); + } else if (NT_STATUS_V(status)) { + uint8_t eclass; + uint32_t ecode; + ntstatus_to_dos(status, &eclass, &ecode); + error_packet_set((char *)req->outbuf, + eclass, ecode, status, + __LINE__,__FILE__); } /* Send the packet */ @@ -1248,7 +1264,7 @@ static void call_trans2open(connection_struct *conn, } /* Send the required number of replies */ - send_trans2_replies(conn, req, params, 30, *ppdata, 0, max_data_bytes); + send_trans2_replies(conn, req, NT_STATUS_OK, params, 30, *ppdata, 0, max_data_bytes); out: TALLOC_FREE(smb_fname); } @@ -2595,7 +2611,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd SSVAL(params,6,0); /* Never an EA error */ SSVAL(params,8,last_entry_off); - send_trans2_replies(conn, req, params, 10, pdata, PTR_DIFF(p,pdata), + send_trans2_replies(conn, req, NT_STATUS_OK, params, 10, pdata, PTR_DIFF(p,pdata), max_data_bytes); if ((! *directory) && dptr_path(sconn, dptr_num)) { @@ -2930,7 +2946,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd SSVAL(params,4,0); /* Never an EA error */ SSVAL(params,6,last_entry_off); - send_trans2_replies(conn, req, params, 8, pdata, PTR_DIFF(p,pdata), + send_trans2_replies(conn, req, NT_STATUS_OK, params, 8, pdata, PTR_DIFF(p,pdata), max_data_bytes); return; @@ -3586,7 +3602,7 @@ static void call_trans2qfsinfo(connection_struct *conn, return; } - send_trans2_replies(conn, req, params, 0, *ppdata, data_len, + send_trans2_replies(conn, req, NT_STATUS_OK, params, 0, *ppdata, data_len, max_data_bytes); DEBUG( 4, ( "%s info_level = %d\n", @@ -3740,6 +3756,7 @@ cap_low = 0x%x, cap_high = 0x%x\n", } send_trans2_replies(conn, req, + NT_STATUS_OK, *pparams, param_len, *ppdata, @@ -4265,7 +4282,7 @@ static void call_trans2qpipeinfo(connection_struct *conn, return; } - send_trans2_replies(conn, req, params, param_size, *ppdata, data_size, + send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size, max_data_bytes); return; @@ -5455,7 +5472,7 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd return; } - send_trans2_replies(conn, req, params, param_size, *ppdata, data_size, + send_trans2_replies(conn, req, NT_STATUS_OK, params, param_size, *ppdata, data_size, max_data_bytes); return; @@ -8054,7 +8071,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, fsp_str_dbg(fsp))); SSVAL(params,0,0); - send_trans2_replies(conn, req, params, 2, + send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes); return; @@ -8180,7 +8197,7 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - send_trans2_replies(conn, req, params, 2, *ppdata, data_return_size, + send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, data_return_size, max_data_bytes); return; @@ -8305,7 +8322,7 @@ static void call_trans2mkdir(connection_struct *conn, struct smb_request *req, SSVAL(params,0,0); - send_trans2_replies(conn, req, params, 2, *ppdata, 0, max_data_bytes); + send_trans2_replies(conn, req, NT_STATUS_OK, params, 2, *ppdata, 0, max_data_bytes); out: TALLOC_FREE(smb_dname); @@ -8360,7 +8377,7 @@ static void call_trans2findnotifyfirst(connection_struct *conn, if(fnf_handle == 0) fnf_handle = 257; - send_trans2_replies(conn, req, params, 6, *ppdata, 0, max_data_bytes); + send_trans2_replies(conn, req, NT_STATUS_OK, params, 6, *ppdata, 0, max_data_bytes); return; } @@ -8391,7 +8408,7 @@ static void call_trans2findnotifynext(connection_struct *conn, SSVAL(params,0,0); /* No changes */ SSVAL(params,2,0); /* No EA errors */ - send_trans2_replies(conn, req, params, 4, *ppdata, 0, max_data_bytes); + send_trans2_replies(conn, req, NT_STATUS_OK, params, 4, *ppdata, 0, max_data_bytes); return; } @@ -8441,7 +8458,7 @@ static void call_trans2getdfsreferral(connection_struct *conn, SSVAL(req->inbuf, smb_flg2, SVAL(req->inbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES); - send_trans2_replies(conn, req,0,0,*ppdata,reply_size, max_data_bytes); + send_trans2_replies(conn, req, NT_STATUS_OK, 0,0,*ppdata,reply_size, max_data_bytes); return; } @@ -8493,7 +8510,7 @@ static void call_trans2ioctl(connection_struct *conn, srvstr_push(pdata, req->flags2, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */ - send_trans2_replies(conn, req, *pparams, 0, *ppdata, 32, + send_trans2_replies(conn, req, NT_STATUS_OK, *pparams, 0, *ppdata, 32, max_data_bytes); return; } -- 1.8.3 From b455d8946d9ced287f27921970f16527239375dc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 10 Jul 2013 12:18:36 -0700 Subject: [PATCH 06/10] Add error map of STATUS_INVALID_EA_NAME -> ERRDOS, ERRbadfile (from Windows2012 tests). Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/libsmb/errormap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/libsmb/errormap.c b/source3/libsmb/errormap.c index bc9676b..7073868 100644 --- a/source3/libsmb/errormap.c +++ b/source3/libsmb/errormap.c @@ -110,6 +110,7 @@ static const struct { */ {ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW}, {ERRDOS, ERRnofiles, STATUS_NO_MORE_FILES}, + {ERRDOS, ERRbadfile, STATUS_INVALID_EA_NAME}, {ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, {ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, {ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, -- 1.8.3 From 0dcd8c6952896d38485d769eab056a79dc5d5902 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 15:59:53 -0700 Subject: [PATCH 07/10] Ensure we can't create a file using TRANS2_OPEN with an invalid EA list. Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/smbd/trans2.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index a87d67f..7449c68 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1189,6 +1189,20 @@ static void call_trans2open(connection_struct *conn, reply_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED); goto out; } + + if (ea_list_has_invalid_name(ea_list)) { + int param_len = 30; + *pparams = (char *)SMB_REALLOC(*pparams, param_len); + if(*pparams == NULL ) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + goto out; + } + params = *pparams; + memset(params, '\0', param_len); + send_trans2_replies(conn, req, STATUS_INVALID_EA_NAME, + params, param_len, NULL, 0, max_data_bytes); + goto out; + } } status = SMB_VFS_CREATE_FILE( -- 1.8.3 From d4b7d232efe603fca6bee7021d3480bf56eb5b72 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 15:54:39 -0700 Subject: [PATCH 08/10] Ensure we can't create a file using NTTRANS with an invalid EA list. Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/smbd/nttrans.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index a884b2f..e986f36 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1143,6 +1143,26 @@ static void call_nt_transact_create(connection_struct *conn, reply_nterror(req, NT_STATUS_INVALID_PARAMETER); goto out; } + + if (ea_list_has_invalid_name(ea_list)) { + /* Realloc the size of parameters and data we will return */ + if (flags & EXTENDED_RESPONSE_REQUIRED) { + /* Extended response is 32 more byyes. */ + param_len = 101; + } else { + param_len = 69; + } + params = nttrans_realloc(ppparams, param_len); + if(params == NULL) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + goto out; + } + + memset(params, '\0', param_len); + send_nt_replies(conn, req, STATUS_INVALID_EA_NAME, + params, param_len, NULL, 0); + goto out; + } } srvstr_get_path(ctx, params, req->flags2, &fname, -- 1.8.3 From ec4cda8025ed30c88929a7f9bb932fe20d090da9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 16 Jul 2013 11:05:10 -0700 Subject: [PATCH 09/10] Ensure we do pathname processing before SD and EA processing in NTTRANS_CREATE. Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/smbd/nttrans.c | 74 +++++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index e986f36..e9c75fa 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1093,6 +1093,43 @@ static void call_nt_transact_create(connection_struct *conn, */ create_options &= ~NTCREATEX_OPTIONS_MUST_IGNORE_MASK; + srvstr_get_path(ctx, params, req->flags2, &fname, + params+53, parameter_count-53, + STR_TERMINATE, &status); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + goto out; + } + + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { + case_state = set_posix_case_semantics(ctx, conn); + if (!case_state) { + reply_nterror(req, NT_STATUS_NO_MEMORY); + goto out; + } + } + + status = filename_convert(ctx, + conn, + req->flags2 & FLAGS2_DFS_PATHNAMES, + fname, + 0, + NULL, + &smb_fname); + + TALLOC_FREE(case_state); + + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { + reply_botherror(req, + NT_STATUS_PATH_NOT_COVERED, + ERRSRV, ERRbadpath); + goto out; + } + reply_nterror(req, status); + goto out; + } + /* Ensure the data_len is correct for the sd and ea values given. */ if ((ea_len + sd_len > data_count) || (ea_len > data_count) || (sd_len > data_count) @@ -1165,43 +1202,6 @@ static void call_nt_transact_create(connection_struct *conn, } } - srvstr_get_path(ctx, params, req->flags2, &fname, - params+53, parameter_count-53, - STR_TERMINATE, &status); - if (!NT_STATUS_IS_OK(status)) { - reply_nterror(req, status); - goto out; - } - - if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { - case_state = set_posix_case_semantics(ctx, conn); - if (!case_state) { - reply_nterror(req, NT_STATUS_NO_MEMORY); - goto out; - } - } - - status = filename_convert(ctx, - conn, - req->flags2 & FLAGS2_DFS_PATHNAMES, - fname, - 0, - NULL, - &smb_fname); - - TALLOC_FREE(case_state); - - if (!NT_STATUS_IS_OK(status)) { - if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) { - reply_botherror(req, - NT_STATUS_PATH_NOT_COVERED, - ERRSRV, ERRbadpath); - goto out; - } - reply_nterror(req, status); - goto out; - } - oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0; if (oplock_request) { oplock_request |= (flags & REQUEST_BATCH_OPLOCK) -- 1.8.3 From 302851a72386d02af90b3de859cd7904c5317515 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 16 Jul 2013 09:14:12 -0700 Subject: [PATCH 10/10] Reply with correct trans2 message on a setpathinfo with a bad EA name. Bug 9992 - Windows error 0x800700FE when copying files with xattr names containing ":" Signed-off-by: Jeremy Allison Reviewed-by: Andrew Bartlett --- source3/smbd/trans2.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 7449c68..43670e9 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -8207,7 +8207,16 @@ static void call_trans2setfilepathinfo(connection_struct *conn, return; } - reply_nterror(req, status); + /* + * Invalid EA name needs to return 2 param bytes, + * not a zero-length error packet. + */ + if (NT_STATUS_EQUAL(status, STATUS_INVALID_EA_NAME)) { + send_trans2_replies(conn, req, status, params, 2, NULL, 0, + max_data_bytes); + } else { + reply_nterror(req, status); + } return; } -- 1.8.3