From 2f52084285adbf088e2464db9628934f13adffd3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 15:50:47 -0700 Subject: [PATCH 01/11] 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 6856dd7..5f34193 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1612,6 +1612,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 9a6ab2b..89bd413 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -232,3 +232,37 @@ bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) return strcasecmp_m(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 3fa4ce59f7e197dbc8c68a4d3ec663e52d1c8c3f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 15:52:47 -0700 Subject: [PATCH 02/11] 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 c129946..ff7bc3e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -622,6 +622,15 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, return NT_STATUS_INVALID_PARAMETER; } + /* + * 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; + } + fname = smb_fname->base_name; for (;ea_list; ea_list = ea_list->next) { -- 1.8.3 From 5863115ecf55d665fcee017a9fd734bc332ec652 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 16:21:18 -0700 Subject: [PATCH 03/11] 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 ff7bc3e..f12bd8f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -344,6 +344,15 @@ static NTSTATUS get_ea_list_from_file_path(TALLOC_CTX *mem_ctx, connection_struc || 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(mem_ctx, struct ea_list); if (listp == NULL) { return NT_STATUS_NO_MEMORY; -- 1.8.3 From 18f1cfa31b69ca902529d9aa88e19f3b152a861c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 16:02:50 -0700 Subject: [PATCH 04/11] 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 c88224e..edbd50f 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -583,6 +583,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 b29778802538c0ee26e8ebc29e5940f41cb2c3c5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 10 Jul 2013 12:38:41 -0700 Subject: [PATCH 05/11] 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 95d6c33..100944c 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -563,7 +563,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 319e20e..b4f4501 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1061,6 +1061,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 f12bd8f..47214e6 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -895,6 +895,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, @@ -935,6 +936,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, @@ -1065,6 +1074,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 */ @@ -1311,7 +1327,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); } @@ -2675,7 +2691,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)) { @@ -3026,7 +3042,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; @@ -3670,7 +3686,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", @@ -3826,6 +3842,7 @@ static void call_trans2setfsinfo(connection_struct *conn, } send_trans2_replies(conn, req, + NT_STATUS_OK, *pparams, param_len, *ppdata, @@ -4358,7 +4375,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; @@ -5563,7 +5580,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; @@ -8128,7 +8145,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; @@ -8255,7 +8272,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; @@ -8380,7 +8397,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); @@ -8435,7 +8452,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; } @@ -8466,7 +8483,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; } @@ -8516,7 +8533,7 @@ static void call_trans2getdfsreferral(connection_struct *conn, SSVAL((discard_const_p(uint8_t, 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; } @@ -8565,7 +8582,7 @@ static void call_trans2ioctl(connection_struct *conn, srvstr_push(pdata, req->flags2, pdata+18, lp_servicename(talloc_tos(), 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 ef6393d060612747628323a096d5d30eb64a893c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 10 Jul 2013 12:18:36 -0700 Subject: [PATCH 06/11] 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 --- libcli/util/errormap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libcli/util/errormap.c b/libcli/util/errormap.c index 714e62c..3870619 100644 --- a/libcli/util/errormap.c +++ b/libcli/util/errormap.c @@ -54,6 +54,7 @@ static const struct { */ {ERRDOS, ERRmoredata, STATUS_BUFFER_OVERFLOW}, {ERRDOS, ERRnofiles, STATUS_NO_MORE_FILES}, + {ERRDOS, ERRbadfile, STATUS_INVALID_EA_NAME}, {ERRDOS, ERRnofiles, NT_STATUS_NO_MORE_ENTRIES}, {ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, -- 1.8.3 From ad9c79241edae07d6a9804ec2c9bd17f924ab2c6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 15:59:53 -0700 Subject: [PATCH 07/11] 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 47214e6..bfcf2f5 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1252,6 +1252,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 896925e95be219c31a0aa21624762f4d7203f6e6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 15:54:39 -0700 Subject: [PATCH 08/11] 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 012bbe0..295699c 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1135,6 +1135,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 0ef6af13d521f1ac8e001219adecb535e501c437 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 16 Jul 2013 11:05:10 -0700 Subject: [PATCH 09/11] 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 295699c..e12961a 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1085,6 +1085,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) @@ -1157,43 +1194,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 b09f0e7a7b6fd8a2568a0ff293595621173f7f1a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 16 Jul 2013 09:14:12 -0700 Subject: [PATCH 10/11] 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 bfcf2f5..6500040 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -8282,7 +8282,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 From 8bf10b71c267031a8d863fb7f8f60d976f1a93f4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 9 Jul 2013 16:37:48 -0700 Subject: [PATCH 11/11] Add torture tests to raw.eas to check sending Windows invalid names in the middle of an EA list. Add torture tests to probe the set of 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 Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Fri Jul 19 11:50:25 CEST 2013 on sn-devel-104 --- selftest/knownfail | 1 + source4/torture/raw/eas.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index 262b889..d249a25 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -65,6 +65,7 @@ ^samba4.raw.session.expire1 ^samba4.raw.rename.*.osxrename ^samba4.raw.rename.*.directory rename +^samba4.raw.eas ^samba4.rpc.winreg.*security ^samba4.local.registry.(dir|ldb).check hive security ^samba4.local.registry.local.security diff --git a/source4/torture/raw/eas.c b/source4/torture/raw/eas.c index a0ba06f..95a55d1 100644 --- a/source4/torture/raw/eas.c +++ b/source4/torture/raw/eas.c @@ -42,6 +42,8 @@ static bool check_ea(struct smbcli_state *cli, return NT_STATUS_IS_OK(status); } +static char bad_ea_chars[] = "\"*+,/:;<=>?[\\]|"; + static bool test_eas(struct smbcli_state *cli, struct torture_context *tctx) { NTSTATUS status; @@ -49,6 +51,8 @@ static bool test_eas(struct smbcli_state *cli, struct torture_context *tctx) union smb_open io; const char *fname = BASEDIR "\\ea.txt"; bool ret = true; + char bad_ea_name[6]; + int i; int fnum = -1; torture_comment(tctx, "TESTING SETFILEINFO EA_SET\n"); @@ -131,6 +135,59 @@ static bool test_eas(struct smbcli_state *cli, struct torture_context *tctx) ret &= check_ea(cli, fname, "EAONE", NULL); ret &= check_ea(cli, fname, "SECONDEA", NULL); + /* Check EA name containing colon. All EA's set + must be ignored, not just the one with the bad + name. */ + + torture_comment(tctx, "Adding bad EA name\n"); + setfile.generic.level = RAW_SFILEINFO_EA_SET; + setfile.generic.in.file.fnum = fnum; + setfile.ea_set.in.num_eas = 3; + setfile.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 3); + setfile.ea_set.in.eas[0].flags = 0; + setfile.ea_set.in.eas[0].name.s = "EAONE"; + setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1"); + setfile.ea_set.in.eas[1].flags = 0; + setfile.ea_set.in.eas[1].name.s = "SECOND:EA"; + setfile.ea_set.in.eas[1].value = data_blob_string_const("ValueTwo"); + setfile.ea_set.in.eas[2].flags = 0; + setfile.ea_set.in.eas[2].name.s = "THIRDEA"; + setfile.ea_set.in.eas[2].value = data_blob_string_const("ValueThree"); + + status = smb_raw_setfileinfo(cli->tree, &setfile); + CHECK_STATUS(status, STATUS_INVALID_EA_NAME); + + ret &= check_ea(cli, fname, "EAONE", NULL); + ret &= check_ea(cli, fname, "THIRDEA", NULL); + + setfile.generic.level = RAW_SFILEINFO_EA_SET; + setfile.generic.in.file.fnum = fnum; + setfile.ea_set.in.num_eas = 1; + setfile.ea_set.in.eas = talloc_array(tctx, struct ea_struct, 1); + setfile.ea_set.in.eas[0].flags = 0; + strlcpy(bad_ea_name, "TEST_X", sizeof(bad_ea_name)); + setfile.ea_set.in.eas[0].name.s = bad_ea_name; + + torture_comment(tctx, "Testing bad EA name range.\n"); + + for (i = 1; i < 256; i++) { + setfile.ea_set.in.eas[0].value = data_blob_string_const("VALUE1"); + bad_ea_name[5] = (char)i; + torture_comment(tctx, "Testing bad EA name %d.\n", i); + status = smb_raw_setfileinfo(cli->tree, &setfile); + if (i < 32 || strchr(bad_ea_chars, i)) { + CHECK_STATUS(status, STATUS_INVALID_EA_NAME); + } else { + CHECK_STATUS(status, NT_STATUS_OK); + + /* Now delete the EA we just set to make + sure we don't run out of room. */ + setfile.ea_set.in.eas[0].value = data_blob(NULL, 0); + status = smb_raw_setfileinfo(cli->tree, &setfile); + CHECK_STATUS(status, NT_STATUS_OK); + } + } + done: smbcli_close(cli->tree, fnum); return ret; @@ -365,6 +422,7 @@ static bool test_nttrans_create(struct smbcli_state *cli, struct torture_context NTSTATUS status; union smb_open io; const char *fname = BASEDIR "\\ea2.txt"; + const char *fname_bad = BASEDIR "\\ea2_bad.txt"; bool ret = true; int fnum = -1; struct ea_struct eas[3]; @@ -434,6 +492,62 @@ static bool test_nttrans_create(struct smbcli_state *cli, struct torture_context ret &= check_ea(cli, fname, "and 3rd", "final value"); ret &= check_ea(cli, fname, "Fourth EA", NULL); + torture_comment(tctx, "TESTING NTTRANS CREATE WITH BAD EA NAMES\n"); + + io.generic.level = RAW_OPEN_NTTRANS_CREATE; + io.ntcreatex.in.root_fid.fnum = 0; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname_bad; + + ea_list.num_eas = 3; + ea_list.eas = eas; + + eas[0].flags = 0; + eas[0].name.s = "1st EA"; + eas[0].value = data_blob_string_const("Value One"); + + eas[1].flags = 0; + eas[1].name.s = "2nd:BAD:EA"; + eas[1].value = data_blob_string_const("Second Value"); + + eas[2].flags = 0; + eas[2].name.s = "and 3rd"; + eas[2].value = data_blob_string_const("final value"); + + io.ntcreatex.in.ea_list = &ea_list; + io.ntcreatex.in.sec_desc = NULL; + + status = smb_raw_open(cli->tree, tctx, &io); + CHECK_STATUS(status, STATUS_INVALID_EA_NAME); + + /* File must not exist. */ + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid.fnum = 0; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io.ntcreatex.in.share_access = + NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname_bad; + status = smb_raw_open(cli->tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND); + done: smbcli_close(cli->tree, fnum); return ret; -- 1.8.3