From d4411af33579e2d73372f8ca53837a62a5f258e7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 12:54:47 -0800 Subject: [PATCH 01/16] CVE-2021-44141: s4: torture: Fix raw.search:test_one_file() to use torture_result() instead of printf. I think this test pre-dates torture_result. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- source4/torture/raw/search.c | 60 ++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c index c7bb88a6d53..083eef47771 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -315,7 +315,11 @@ static bool test_one_file(struct torture_context *tctx, fnum = create_complex_file(cli, tctx, fname); if (fnum == -1) { - printf("ERROR: open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree)); + torture_result(tctx, + TORTURE_FAIL, + __location__"ERROR: open of %s failed (%s)\n", + fname, + smbcli_errstr(cli->tree)); ret = false; goto done; } @@ -342,9 +346,11 @@ static bool test_one_file(struct torture_context *tctx, } if (!NT_STATUS_IS_OK(levels[i].status)) { - printf("search level %s(%d) failed - %s\n", - levels[i].name, (int)levels[i].level, - nt_errstr(levels[i].status)); + torture_result(tctx, + TORTURE_FAIL, + __location__"search level %s(%d) failed - %s\n", + levels[i].name, (int)levels[i].level, + nt_errstr(levels[i].status)); ret = false; continue; } @@ -362,7 +368,9 @@ static bool test_one_file(struct torture_context *tctx, expected_status = STATUS_NO_MORE_FILES; } if (!NT_STATUS_EQUAL(status, expected_status)) { - printf("search level %s(%d) should fail with %s - %s\n", + torture_result(tctx, + TORTURE_FAIL, + __location__"search level %s(%d) should fail with %s - %s\n", levels[i].name, (int)levels[i].level, nt_errstr(expected_status), nt_errstr(status)); @@ -399,8 +407,10 @@ static bool test_one_file(struct torture_context *tctx, s = find(name); \ if (s) { \ if ((s->sname1.field1) != (v.sname2.out.field2)) { \ - printf("(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \ - __location__, \ + torture_result(tctx,\ + TORTURE_FAIL,\ + "(%s) %s/%s [0x%x] != %s/%s [0x%x]\n", \ + __location__, \ #sname1, #field1, (int)s->sname1.field1, \ #sname2, #field2, (int)v.sname2.out.field2); \ ret = false; \ @@ -411,8 +421,10 @@ static bool test_one_file(struct torture_context *tctx, s = find(name); \ if (s) { \ if (s->sname1.field1 != (~1 & nt_time_to_unix(v.sname2.out.field2))) { \ - printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ - __location__, \ + torture_result(tctx,\ + TORTURE_FAIL,\ + "(%s) %s/%s [%s] != %s/%s [%s]\n", \ + __location__, \ #sname1, #field1, timestring(tctx, s->sname1.field1), \ #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \ ret = false; \ @@ -423,8 +435,10 @@ static bool test_one_file(struct torture_context *tctx, s = find(name); \ if (s) { \ if (s->sname1.field1 != v.sname2.out.field2) { \ - printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ - __location__, \ + torture_result(tctx,\ + TORTURE_FAIL,\ + "(%s) %s/%s [%s] != %s/%s [%s]\n", \ + __location__, \ #sname1, #field1, nt_time_string(tctx, s->sname1.field1), \ #sname2, #field2, nt_time_string(tctx, v.sname2.out.field2)); \ ret = false; \ @@ -435,8 +449,10 @@ static bool test_one_file(struct torture_context *tctx, s = find(name); \ if (s) { \ if (!s->sname1.field1 || strcmp(s->sname1.field1, v.sname2.out.field2.s)) { \ - printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ - __location__, \ + torture_result(tctx,\ + TORTURE_FAIL,\ + "(%s) %s/%s [%s] != %s/%s [%s]\n", \ + __location__, \ #sname1, #field1, s->sname1.field1, \ #sname2, #field2, v.sname2.out.field2.s); \ ret = false; \ @@ -449,8 +465,10 @@ static bool test_one_file(struct torture_context *tctx, if (!s->sname1.field1.s || \ strcmp(s->sname1.field1.s, v.sname2.out.field2.s) || \ wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \ - printf("(%s) %s/%s [%s] != %s/%s [%s]\n", \ - __location__, \ + torture_result(tctx,\ + TORTURE_FAIL,\ + "(%s) %s/%s [%s] != %s/%s [%s]\n", \ + __location__, \ #sname1, #field1, s->sname1.field1.s, \ #sname2, #field2, v.sname2.out.field2.s); \ ret = false; \ @@ -463,8 +481,10 @@ static bool test_one_file(struct torture_context *tctx, if (!s->sname1.field1.s || \ strcmp(s->sname1.field1.s, fname) || \ wire_bad_flags(&s->sname1.field1, flags, cli->transport)) { \ - printf("(%s) %s/%s [%s] != %s\n", \ - __location__, \ + torture_result(tctx,\ + TORTURE_FAIL,\ + "(%s) %s/%s [%s] != %s\n", \ + __location__, \ #sname1, #field1, s->sname1.field1.s, \ fname); \ ret = false; \ @@ -476,8 +496,10 @@ static bool test_one_file(struct torture_context *tctx, if (s) { \ if (!s->sname1.field1 || \ strcmp(s->sname1.field1, fname)) { \ - printf("(%s) %s/%s [%s] != %s\n", \ - __location__, \ + torture_result(tctx,\ + TORTURE_FAIL,\ + "(%s) %s/%s [%s] != %s\n", \ + __location__, \ #sname1, #field1, s->sname1.field1, \ fname); \ ret = false; \ -- 2.30.2 From 3a3c2f1b13b8527b9e265fab88350aa6b7ee381c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 14:18:47 -0800 Subject: [PATCH 02/16] CVE-2021-44141: s4: torture: In raw.search:test_one_file() remove the leading '\\' in the test filenames. We'll soon be using this under SMB1+POSIX and neither Windows or POSIX need a leading '\\' (and SMB1+POSIX sees the '\\' as part of the name). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- source4/torture/raw/search.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c index 083eef47771..b18c25968ae 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -304,8 +304,8 @@ static bool test_one_file(struct torture_context *tctx, { bool ret = true; int fnum; - const char *fname = "\\torture_search.txt"; - const char *fname2 = "\\torture_search-NOTEXIST.txt"; + const char *fname = "torture_search.txt"; + const char *fname2 = "torture_search-NOTEXIST.txt"; NTSTATUS status; int i; union smb_fileinfo all_info, alt_info, name_info, internal_info; @@ -580,20 +580,20 @@ static bool test_one_file(struct torture_context *tctx, short_name, alt_info, alt_name_info, fname, STR_UNICODE); } - CHECK_NAME("STANDARD", standard, name, fname+1, 0); - CHECK_NAME("EA_SIZE", ea_size, name, fname+1, 0); - CHECK_NAME("DIRECTORY_INFO", directory_info, name, fname+1, STR_TERMINATE_ASCII); - CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname+1, STR_TERMINATE_ASCII); + CHECK_NAME("STANDARD", standard, name, fname, 0); + CHECK_NAME("EA_SIZE", ea_size, name, fname, 0); + CHECK_NAME("DIRECTORY_INFO", directory_info, name, fname, STR_TERMINATE_ASCII); + CHECK_NAME("FULL_DIRECTORY_INFO", full_directory_info, name, fname, STR_TERMINATE_ASCII); if (name_info_supported) { - CHECK_NAME("NAME_INFO", name_info, name, fname+1, + CHECK_NAME("NAME_INFO", name_info, name, fname, STR_TERMINATE_ASCII); } - CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname+1, STR_TERMINATE_ASCII); - CHECK_NAME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, name, fname+1, STR_TERMINATE_ASCII); - CHECK_NAME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, name, fname+1, STR_TERMINATE_ASCII); - CHECK_UNIX_NAME("UNIX_INFO", unix_info, name, fname+1, STR_TERMINATE_ASCII); + CHECK_NAME("BOTH_DIRECTORY_INFO", both_directory_info, name, fname, STR_TERMINATE_ASCII); + CHECK_NAME("ID_FULL_DIRECTORY_INFO", id_full_directory_info, name, fname, STR_TERMINATE_ASCII); + CHECK_NAME("ID_BOTH_DIRECTORY_INFO", id_both_directory_info, name, fname, STR_TERMINATE_ASCII); + CHECK_UNIX_NAME("UNIX_INFO", unix_info, name, fname, STR_TERMINATE_ASCII); if (internal_info_supported) { CHECK_VAL("ID_FULL_DIRECTORY_INFO", id_full_directory_info, -- 2.30.2 From 9659c31b9a8c14d39cef2f50a9f02e850d00cfd8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 18 Nov 2021 11:48:42 -0800 Subject: [PATCH 03/16] CVE-2021-44141: s3: smbd: Tighten up info level checks for SMB1+POSIX to make sure POSIX was negotiated first. Add knownfail file knownfail.d/posix_infolevel_fails for tests that don't currently negotiate SMB1+POSIX before using SMB1+POSIX calls. These are: samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\) samba3.blackbox.acl_xattr.NT1.nt_affects_posix.* samba3.blackbox.acl_xattr.NT1.nt_affects_chown.* samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.* samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.* samba3.unix.info2.info2\(nt4_dc_smb1\) samba3.unix.info2.info2\(ad_dc_smb1\) samba3.raw.search.one\ file\ search.* BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_infolevel_fails | 8 +++ source3/smbd/trans2.c | 65 +++++++++++++++++++--- 2 files changed, 66 insertions(+), 7 deletions(-) create mode 100644 selftest/knownfail.d/posix_infolevel_fails diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails new file mode 100644 index 00000000000..78a6781684c --- /dev/null +++ b/selftest/knownfail.d/posix_infolevel_fails @@ -0,0 +1,8 @@ +^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\) +^samba3.blackbox.acl_xattr.NT1.nt_affects_posix.* +^samba3.blackbox.acl_xattr.NT1.nt_affects_chown.* +^samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.* +^samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.* +^samba3.unix.info2.info2\(nt4_dc_smb1\) +^samba3.unix.info2.info2\(ad_dc_smb1\) +^samba3.raw.search.one\ file\ search.* diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 7acde285a90..660687e0d7b 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -2793,6 +2793,10 @@ close_if_end = %d requires_resume_key = %d backup_priv = %d level = 0x%x, max_da reply_nterror(req, NT_STATUS_INVALID_LEVEL); goto out; } + if (!req->posix_pathnames) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + goto out; + } ucf_flags |= UCF_UNIX_NAME_LOOKUP; break; default: @@ -3322,6 +3326,10 @@ resume_key = %d resume name = %s continue=%d level = %d\n", reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; } + if (!req->posix_pathnames) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } break; default: reply_nterror(req, NT_STATUS_INVALID_LEVEL); @@ -5215,8 +5223,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, uint32_t access_mask = 0; size_t len = 0; - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - return NT_STATUS_INVALID_LEVEL; + if (INFO_LEVEL_IS_UNIX(info_level)) { + if (!lp_unix_extensions()) { + return NT_STATUS_INVALID_LEVEL; + } + if (!req->posix_pathnames) { + return NT_STATUS_INVALID_LEVEL; + } } DEBUG(5,("smbd_do_qfilepathinfo: %s (%s) level=%d max_data=%u\n", @@ -6049,9 +6062,15 @@ static void call_trans2qfilepathinfo(connection_struct *conn, DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + if (INFO_LEVEL_IS_UNIX(info_level)) { + if (!lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + if (!req->posix_pathnames) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } } /* Initial check for valid fsp ptr. */ @@ -6148,6 +6167,10 @@ static void call_trans2qfilepathinfo(connection_struct *conn, reply_nterror(req, NT_STATUS_INVALID_LEVEL); return; } + if (!req->posix_pathnames) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } if (info_level == SMB_QUERY_FILE_UNIX_BASIC || info_level == SMB_QUERY_FILE_UNIX_INFO2 || info_level == SMB_QUERY_FILE_UNIX_LINK || @@ -8995,8 +9018,13 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, *ret_data_size = 0; - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - return NT_STATUS_INVALID_LEVEL; + if (INFO_LEVEL_IS_UNIX(info_level)) { + if (!lp_unix_extensions()) { + return NT_STATUS_INVALID_LEVEL; + } + if (!req->posix_pathnames) { + return NT_STATUS_INVALID_LEVEL; + } } if (!CAN_WRITE(conn)) { @@ -9308,6 +9336,17 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } info_level = SVAL(params,2); + if (INFO_LEVEL_IS_UNIX(info_level)) { + if (!lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + if (!req->posix_pathnames) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + } + smb_fname = cp_smb_filename(talloc_tos(), fsp->fsp_name); if (smb_fname == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); @@ -9385,6 +9424,18 @@ static void call_trans2setfilepathinfo(connection_struct *conn, } info_level = SVAL(params,0); + + if (INFO_LEVEL_IS_UNIX(info_level)) { + if (!lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + if (!req->posix_pathnames) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + } + if (req->posix_pathnames) { srvstr_get_path_posix(req, params, -- 2.30.2 From 2475c146539051f58847ba1bd6ec64fe3ec394a5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Sat, 20 Nov 2021 20:17:11 -0800 Subject: [PATCH 04/16] CVE-2021-44141: s3: smbclient: Give a message if we try and use any POSIX command without negotiating POSIX first. Ensure we only use a POSIX command if POSIX is set up. Issue the message: Command "posix" must be issued before the "XXXX" command can be used. After the parameter parsing has been done. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- source3/client/client.c | 79 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/source3/client/client.c b/source3/client/client.c index 8c7ceb644aa..d7ead9055a5 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -2798,6 +2798,11 @@ static int cmd_posix_open(void) d_printf("posix_open 0\n"); return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"posix_open\" command can be used.\n"); + return 1; + } mode = (mode_t)strtol(buf, (char **)NULL, 8); status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(), @@ -2857,6 +2862,11 @@ static int cmd_posix_mkdir(void) d_printf("posix_mkdir 0\n"); return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"posix_mkdir\" command can be used.\n"); + return 1; + } mode = (mode_t)strtol(buf, (char **)NULL, 8); status = cli_resolve_path(ctx, "", popt_get_cmdline_auth_info(), @@ -2889,6 +2899,11 @@ static int cmd_posix_unlink(void) d_printf("posix_unlink \n"); return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"posix_unlink\" command can be used.\n"); + return 1; + } mask = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(), @@ -2932,6 +2947,11 @@ static int cmd_posix_rmdir(void) d_printf("posix_rmdir \n"); return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"posix_rmdir\" command can be used.\n"); + return 1; + } mask = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(), @@ -3130,6 +3150,12 @@ static int cmd_lock(void) return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"lock\" command can be used.\n"); + return 1; + } + len = (uint64_t)strtol(buf, (char **)NULL, 16); status = cli_posix_lock(cli, fnum, start, len, true, lock_type); @@ -3166,6 +3192,12 @@ static int cmd_unlock(void) return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"unlock\" command can be used.\n"); + return 1; + } + len = (uint64_t)strtol(buf, (char **)NULL, 16); status = cli_posix_unlock(cli, fnum, start, len); @@ -3189,6 +3221,12 @@ static int cmd_posix_whoami(void) bool guest = false; uint32_t i; + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"posix_whoami\" command can be used.\n"); + return 1; + } + status = cli_posix_whoami(cli, ctx, &uid, @@ -3322,6 +3360,12 @@ static int cmd_link(void) return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"link\" command can be used.\n"); + return 1; + } + status = cli_posix_hardlink(targetcli, targetname, newname); if (!NT_STATUS_IS_OK(status)) { d_printf("%s linking files (%s -> %s)\n", @@ -3373,6 +3417,12 @@ static int cmd_readlink(void) return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"readlink\" command can be used.\n"); + return 1; + } + status = cli_posix_readlink(targetcli, name, talloc_tos(), &linkname); if (!NT_STATUS_IS_OK(status)) { d_printf("%s readlink on file %s\n", @@ -3411,6 +3461,11 @@ static int cmd_symlink(void) link_target = buf; if (SERVER_HAS_UNIX_CIFS(cli)) { + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"symlink\" command can be used.\n"); + return 1; + } newname = talloc_asprintf(ctx, "%s%s", client_get_cur_dir(), buf2); if (!newname) { @@ -3491,6 +3546,12 @@ static int cmd_chmod(void) return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"chmod\" command can be used.\n"); + return 1; + } + status = cli_posix_chmod(targetcli, targetname, mode); if (!NT_STATUS_IS_OK(status)) { d_printf("%s chmod file %s 0%o\n", @@ -3653,6 +3714,12 @@ static int cmd_getfacl(void) return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"getfacl\" command can be used.\n"); + return 1; + } + status = cli_unix_extensions_version(targetcli, &major, &minor, &caplow, &caphigh); if (!NT_STATUS_IS_OK(status)) { @@ -3946,6 +4013,12 @@ static int cmd_stat(void) return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"stat\" command can be used.\n"); + return 1; + } + status = cli_posix_stat(targetcli, targetname, &sbuf); if (!NT_STATUS_IS_OK(status)) { d_printf("%s stat file %s\n", @@ -4058,6 +4131,12 @@ static int cmd_chown(void) return 1; } + if (CLI_DIRSEP_CHAR != '/') { + d_printf("Command \"posix\" must be issued before " + "the \"chown\" command can be used.\n"); + return 1; + } + status = cli_posix_chown(targetcli, targetname, uid, gid); if (!NT_STATUS_IS_OK(status)) { d_printf("%s chown file %s uid=%d, gid=%d\n", -- 2.30.2 From da45aef8e25ab2b78f6318ce201e9c57a66754a7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 14:44:05 -0800 Subject: [PATCH 05/16] CVE-2021-44141: s4: torture: In raw.search:test_one_file() add a second connection. Change from torture_suite_add_1smb_test() to torture_suite_add_2smb_test(). Not yet used. We will need this to do SMB1+POSIX search calls on a connection on which we have negotiated SMB1+POSIX. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- source4/torture/raw/search.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c index b18c25968ae..7e641e17be2 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -299,8 +299,9 @@ static union smb_search_data *find(const char *name) /* basic testing of all RAW_SEARCH_* calls using a single file */ -static bool test_one_file(struct torture_context *tctx, - struct smbcli_state *cli) +static bool test_one_file(struct torture_context *tctx, + struct smbcli_state *cli, + struct smbcli_state *cli_unix) { bool ret = true; int fnum; @@ -1570,7 +1571,7 @@ struct torture_suite *torture_raw_search(TALLOC_CTX *mem_ctx) { struct torture_suite *suite = torture_suite_create(mem_ctx, "search"); - torture_suite_add_1smb_test(suite, "one file search", test_one_file); + torture_suite_add_2smb_test(suite, "one file search", test_one_file); torture_suite_add_1smb_test(suite, "many files", test_many_files); torture_suite_add_1smb_test(suite, "sorted", test_sorted); torture_suite_add_1smb_test(suite, "modify search", test_modify_search); -- 2.30.2 From 5cfb2e0834ed9652355d994573bcc0bd77eea006 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 14:48:20 -0800 Subject: [PATCH 06/16] CVE-2021-44141: s4: torture: raw.search: Add setup_smb1_posix(). Call it on the second connection in test_one_file(). Not yet used. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- source4/torture/raw/search.c | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c index 7e641e17be2..3534af25b44 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -296,6 +296,55 @@ static union smb_search_data *find(const char *name) return NULL; } +/* + * Negotiate SMB1+POSIX. + */ + +static NTSTATUS setup_smb1_posix(struct torture_context *tctx, + struct smbcli_state *cli_unix) +{ + struct smb_trans2 tp; + uint16_t setup; + uint8_t data[12]; + uint8_t params[4]; + uint32_t cap = cli_unix->transport->negotiate.capabilities; + + if ((cap & CAP_UNIX) == 0) { + /* + * Server doesn't support SMB1+POSIX. + * The caller will skip the UNIX info + * level anyway. + */ + torture_comment(tctx, + "Server doesn't support SMB1+POSIX\n"); + return NT_STATUS_OK; + } + + /* Setup POSIX on this connection. */ + SSVAL(data, 0, CIFS_UNIX_MAJOR_VERSION); + SSVAL(data, 2, CIFS_UNIX_MINOR_VERSION); + SBVAL(data,4,((uint64_t)( + CIFS_UNIX_POSIX_ACLS_CAP| + CIFS_UNIX_POSIX_PATHNAMES_CAP| + CIFS_UNIX_FCNTL_LOCKS_CAP| + CIFS_UNIX_EXTATTR_CAP| + CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP))); + setup = TRANSACT2_SETFSINFO; + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.max_param = 0; + tp.in.max_data = 0; + tp.in.setup = &setup; + tp.in.trans_name = NULL; + SSVAL(params, 0, 0); + SSVAL(params, 2, SMB_SET_CIFS_UNIX_INFO); + tp.in.params = data_blob_talloc(tctx, params, 4); + tp.in.data = data_blob_talloc(tctx, data, 12); + return smb_raw_trans2(cli_unix->tree, tctx, &tp); +} + /* basic testing of all RAW_SEARCH_* calls using a single file */ @@ -314,6 +363,16 @@ static bool test_one_file(struct torture_context *tctx, internal_info_supported; union smb_search_data *s; + status = setup_smb1_posix(tctx, cli_unix); + if (!NT_STATUS_IS_OK(status)) { + torture_result(tctx, + TORTURE_FAIL, + __location__"setup_smb1_posix() failed (%s)\n", + nt_errstr(status)); + ret = false; + goto done; + } + fnum = create_complex_file(cli, tctx, fname); if (fnum == -1) { torture_result(tctx, -- 2.30.2 From 6977c8d2a7e0da739c0851b7fb4d8227f2c98e34 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 14:51:39 -0800 Subject: [PATCH 07/16] CVE-2021-44141: s4: torture: Fix raw.search:test_one_file() by using the SMB1+POSIX connection for POSIX info levels. Remove the following entry in knownfail.d/posix_infolevel_fails. ^samba3.raw.search.one\ file\ search.* from knownfail.d/posix_infolevel_fails BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_infolevel_fails | 1 - source4/torture/raw/search.c | 13 +++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails index 78a6781684c..4ce4a9cec91 100644 --- a/selftest/knownfail.d/posix_infolevel_fails +++ b/selftest/knownfail.d/posix_infolevel_fails @@ -5,4 +5,3 @@ ^samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.* ^samba3.unix.info2.info2\(nt4_dc_smb1\) ^samba3.unix.info2.info2\(ad_dc_smb1\) -^samba3.raw.search.one\ file\ search.* diff --git a/source4/torture/raw/search.c b/source4/torture/raw/search.c index 3534af25b44..06cc7dfbdbd 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -388,10 +388,19 @@ static bool test_one_file(struct torture_context *tctx, for (i=0;itransport->negotiate.capabilities; + struct smbcli_state *cli_search = cli; torture_comment(tctx, "Testing %s\n", levels[i].name); - levels[i].status = torture_single_search(cli, tctx, fname, + if (levels[i].data_level == RAW_SEARCH_DATA_UNIX_INFO) { + /* + * For an SMB1+POSIX info level, use the cli_unix + * connection. + */ + cli_search = cli_unix; + } + + levels[i].status = torture_single_search(cli_search, tctx, fname, levels[i].level, levels[i].data_level, 0, @@ -415,7 +424,7 @@ static bool test_one_file(struct torture_context *tctx, continue; } - status = torture_single_search(cli, tctx, fname2, + status = torture_single_search(cli_search, tctx, fname2, levels[i].level, levels[i].data_level, 0, -- 2.30.2 From 4b6abc8a8be5e228b90c1bc2d6281a60e5f39101 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 12:15:06 -0800 Subject: [PATCH 08/16] CVE-2021-44141: s4: torture: Fix unix.info2 test to actually negotiate SMB1+POSIX before using POSIX calls. Cope with the minor difference in wildcard search return when we're actually using SMB1+POSIX on the server (SMB1+POSIX treats all directory search paths as wildcards). Remove the following entries in knownfail.d/posix_infolevel_fails. samba3.unix.info2.info2\(nt4_dc_smb1\) samba3.unix.info2.info2\(ad_dc_smb1\) BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_infolevel_fails | 2 -- source4/torture/unix/unix_info2.c | 42 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails index 4ce4a9cec91..3bfff110771 100644 --- a/selftest/knownfail.d/posix_infolevel_fails +++ b/selftest/knownfail.d/posix_infolevel_fails @@ -3,5 +3,3 @@ ^samba3.blackbox.acl_xattr.NT1.nt_affects_chown.* ^samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.* ^samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.* -^samba3.unix.info2.info2\(nt4_dc_smb1\) -^samba3.unix.info2.info2\(ad_dc_smb1\) diff --git a/source4/torture/unix/unix_info2.c b/source4/torture/unix/unix_info2.c index 069a5818e13..dafe9562ad7 100644 --- a/source4/torture/unix/unix_info2.c +++ b/source4/torture/unix/unix_info2.c @@ -19,6 +19,7 @@ #include "includes.h" #include "libcli/libcli.h" +#include "libcli/raw/raw_proto.h" #include "torture/util.h" #include "torture/unix/proto.h" #include "lib/cmdline/popt_common.h" @@ -53,6 +54,10 @@ static struct smbcli_state *connect_to_server(struct torture_context *tctx) const char *share = torture_setting_string(tctx, "share", NULL); struct smbcli_options options; struct smbcli_session_options session_options; + struct smb_trans2 tp; + uint16_t setup; + uint8_t data[12]; + uint8_t params[4]; lpcfg_smbcli_options(tctx->lp_ctx, &options); lpcfg_smbcli_session_options(tctx->lp_ctx, &session_options); @@ -72,6 +77,33 @@ static struct smbcli_state *connect_to_server(struct torture_context *tctx) return NULL; } + /* Setup POSIX on the server. */ + SSVAL(data, 0, CIFS_UNIX_MAJOR_VERSION); + SSVAL(data, 2, CIFS_UNIX_MINOR_VERSION); + SBVAL(data,4,((uint64_t)( + CIFS_UNIX_POSIX_ACLS_CAP| + CIFS_UNIX_POSIX_PATHNAMES_CAP| + CIFS_UNIX_FCNTL_LOCKS_CAP| + CIFS_UNIX_EXTATTR_CAP| + CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP))); + setup = TRANSACT2_SETFSINFO; + tp.in.max_setup = 0; + tp.in.flags = 0; + tp.in.timeout = 0; + tp.in.setup_count = 1; + tp.in.max_param = 0; + tp.in.max_data = 0; + tp.in.setup = &setup; + tp.in.trans_name = NULL; + SSVAL(params, 0, 0); + SSVAL(params, 2, SMB_SET_CIFS_UNIX_INFO); + tp.in.params = data_blob_talloc(tctx, params, 4); + tp.in.data = data_blob_talloc(tctx, data, 12); + + status = smb_raw_trans2(cli->tree, tctx, &tp); + torture_assert_ntstatus_equal(tctx, status, NT_STATUS_OK, + "doing SMB_SET_CIFS_UNIX_INFO"); + return cli; } @@ -245,8 +277,14 @@ static bool find_single_info2(void *mem_ctx, torture_assert_int_equal(torture, search.t2ffirst.out.count, 1, "expected exactly one result"); - torture_assert_int_equal(torture, search.t2ffirst.out.end_of_search, 1, - "expected end_of_search to be true"); + /* + * In smbd directory listings using POSIX extensions + * always treat the search pathname as a wildcard, + * so don't expect end_of_search to be set here. Wildcard + * searches always need a findnext to end the search. + */ + torture_assert_int_equal(torture, search.t2ffirst.out.end_of_search, 0, + "expected end_of_search to be false"); return check_unix_info2(torture, info2); } -- 2.30.2 From a7091749985c686f28749b77326e7ba13dc9ea03 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 12:12:36 -0800 Subject: [PATCH 09/16] CVE-2021-44141: s3: tests: Fix the samba3.blackbox.inherit_owner test to actually negotiate SMB1+POSIX before using POSIX calls. Remove the following entry in knownfail.d/posix_infolevel_fails. samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.* BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_infolevel_fails | 1 - source3/script/tests/test_inherit_owner.sh | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails index 3bfff110771..a865a2055b2 100644 --- a/selftest/knownfail.d/posix_infolevel_fails +++ b/selftest/knownfail.d/posix_infolevel_fails @@ -2,4 +2,3 @@ ^samba3.blackbox.acl_xattr.NT1.nt_affects_posix.* ^samba3.blackbox.acl_xattr.NT1.nt_affects_chown.* ^samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.* -^samba3.blackbox.inherit_owner.*.NT1.*verify.*unix\ owner.* diff --git a/source3/script/tests/test_inherit_owner.sh b/source3/script/tests/test_inherit_owner.sh index 7e1333787aa..9783235883c 100755 --- a/source3/script/tests/test_inherit_owner.sh +++ b/source3/script/tests/test_inherit_owner.sh @@ -79,7 +79,7 @@ unix_owner_id_is() { local fname=$2 local expected_id=$3 local actual_id - actual_id=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null | sed -rn 's/^# owner: (.*)/\1/p') + actual_id=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null | sed -rn 's/^# owner: (.*)/\1/p') if ! test "x$actual_id" = "x$expected_id" ; then echo "Actual uid of $share/$fname is [$actual_id] expected [$expected_id]" exit 1 -- 2.30.2 From 9e67f8021f73c42a3d5da274b67545f46a8f5b01 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 00:05:35 -0800 Subject: [PATCH 10/16] CVE-2021-44141: s3: tests: Fix the samba3.blackbox.acl_xattr test to actually negotiate SMB1+POSIX before using POSIX calls. Remove the following entries in knownfail.d/posix_infolevel_fails. samba3.blackbox.acl_xattr.NT1.nt_affects_posix.* samba3.blackbox.acl_xattr.NT1.nt_affects_chown.* samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.* BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_infolevel_fails | 3 --- source3/script/tests/test_acl_xattr.sh | 12 ++++++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails index a865a2055b2..bf8a884cb16 100644 --- a/selftest/knownfail.d/posix_infolevel_fails +++ b/selftest/knownfail.d/posix_infolevel_fails @@ -1,4 +1 @@ ^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\) -^samba3.blackbox.acl_xattr.NT1.nt_affects_posix.* -^samba3.blackbox.acl_xattr.NT1.nt_affects_chown.* -^samba3.blackbox.acl_xattr.NT1.nt_affects_chgrp.* diff --git a/source3/script/tests/test_acl_xattr.sh b/source3/script/tests/test_acl_xattr.sh index f134ff79c91..8abd7476244 100755 --- a/source3/script/tests/test_acl_xattr.sh +++ b/source3/script/tests/test_acl_xattr.sh @@ -55,9 +55,9 @@ nt_affects_posix() { local b4 local af local fname="$share.$$" - b4=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1 + b4=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1 $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -a "ACL:$SERVER\force_user:ALLOWED/0x0/READ" 2>/dev/null || exit 1 - af=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1 + af=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1 echo "before: $b4" echo "after: $af" echo "${b4}" | grep -q "^# owner:" || exit 1 @@ -90,12 +90,12 @@ nt_affects_chown() { #basic sanity... test "$b4_expected != $af_expected" || exit 1 - b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1 + b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1 echo "${b4_actual}" | grep -q "^# owner:" || exit 1 b4_actual=$(echo "$b4_actual" | sed -rn 's/^# owner: (.*)/\1/p') $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -a "ACL:$SERVER\force_user:ALLOWED/0x0/FULL" || exit 1 $SMBCACLS //$SERVER/$share $fname -U force_user%$PASSWORD -C force_user 2>/dev/null || exit 1 - af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1 + af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1 echo "${af_actual}" | grep -q "^# owner:" || exit 1 af_actual=$(echo "$af_actual" | sed -rn 's/^# owner: (.*)/\1/p') echo "before: $b4_actual" @@ -124,11 +124,11 @@ nt_affects_chgrp() { #basic sanity... test "$b4_expected" != "$af_expected" || exit 1 - b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1 + b4_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1 echo "${b4_actual}" | grep -q "^# group:" || exit 1 b4_actual=$(echo "$b4_actual" | sed -rn 's/^# group: (.*)/\1/p') $SMBCACLS //$SERVER/$share $fname -U $USERNAME%$PASSWORD -G domadmins 2>/dev/null || exit 1 - af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "getfacl $fname" 2>/dev/null) || exit 1 + af_actual=$($SMBCLIENT //$SERVER/$share -U $USERNAME%$PASSWORD -c "posix; getfacl $fname" 2>/dev/null) || exit 1 echo "${af_actual}" | grep -q "^# group:" || exit 1 af_actual=$(echo "$af_actual" | sed -rn 's/^# group: (.*)/\1/p') echo "before: $b4_actual" -- 2.30.2 From 1855fed71f23ab06efb4b0eec6814271296297fc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 18 Nov 2021 12:16:44 -0800 Subject: [PATCH 11/16] CVE-2021-44141: s3: smbtorture3: Fix POSIX-BLOCKING-LOCK to actually negotiate SMB1+POSIX before using POSIX calls. This must be done before doing POSIX calls on a connection. Remove the final entry in knownfail.d/posix_infolevel_fails samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\) And remove the file knownfail.d/posix_infolevel_fails itself. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_infolevel_fails | 1 - source3/torture/torture.c | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) delete mode 100644 selftest/knownfail.d/posix_infolevel_fails diff --git a/selftest/knownfail.d/posix_infolevel_fails b/selftest/knownfail.d/posix_infolevel_fails deleted file mode 100644 index bf8a884cb16..00000000000 --- a/selftest/knownfail.d/posix_infolevel_fails +++ /dev/null @@ -1 +0,0 @@ -^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK.smbtorture\(nt4_dc_smb1\) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 5e263797730..38a9330cac7 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -8892,6 +8892,11 @@ static bool run_posix_blocking_lock(int dummy) return false; } + status = torture_setup_unix_extensions(cli2); + if (!NT_STATUS_IS_OK(status)) { + return false; + } + cli_setatr(cli1, fname, 0, 0); cli_posix_unlink(cli1, fname); -- 2.30.2 From d61a6382b6f581021298ad2feee1438b4ad692a8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 18 Nov 2021 16:57:18 -0800 Subject: [PATCH 12/16] CVE-2021-44141: s3: smbtorture3: Add test POSIX-SYMLINK-ERRORCODE to ensure we always get NT_STATUS_OBJECT_NAME_NOT_FOUND for dangling or unavailable symlinks. Creates 3 symlinks inside the share: 1). Within share pointing to non-existing target. "nonexist_errorcode_symlink" -> "nonexist_errorcode_target" 2). Outside share but to existing target. "tmp_symlink" -> "/tmp" 3). Outside share but to non-existing target. "tmp_noexist_symlink" -> "/tmp/XXX" It then tries to SMB1+POSIX stat these objects, all should succeed. It then tries to open via 3 methods: 1). SMB1+POSIX cli_posix_open() 2). SMB1 Windows cli_ntcreate() 3). SMB2 Windows cli_ntcreate() Ensure we always get NT_STATUS_OBJECT_NAME_NOT_FOUND for all return codes. Add knownfail for normal tests, and make sure we skip for ad_dc_ntvfs as it doesn't support SMB1+POSIX. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_symlink_errorcode | 2 + selftest/skip | 1 + source3/selftest/tests.py | 1 + source3/torture/torture.c | 304 +++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 selftest/knownfail.d/posix_symlink_errorcode diff --git a/selftest/knownfail.d/posix_symlink_errorcode b/selftest/knownfail.d/posix_symlink_errorcode new file mode 100644 index 00000000000..e2e5d28be5c --- /dev/null +++ b/selftest/knownfail.d/posix_symlink_errorcode @@ -0,0 +1,2 @@ +^samba3.smbtorture_s3.plain.POSIX-SYMLINK-ERRORCODE.smbtorture\(nt4_dc_smb1\) +^samba3.smbtorture_s3.crypt.POSIX-SYMLINK-ERRORCODE.smbtorture\(nt4_dc_smb1\) diff --git a/selftest/skip b/selftest/skip index d13cf7cd18b..06d75ba088e 100644 --- a/selftest/skip +++ b/selftest/skip @@ -52,6 +52,7 @@ ^samba3.smbtorture_s3.plain.POSIX-ACL-OPLOCK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.POSIX-ACL-SHAREROOT\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server +^samba3.smbtorture_s3.plain.POSIX-SYMLINK-ERRORCODE.*\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.WINDOWS-BAD-SYMLINK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.RENAME-ACCESS\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.OWNER-RIGHTS\(ad_dc_ntvfs\) # Don't test against the s4 ntvfs server anymore diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 47e914b1009..8706c6e209f 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -215,6 +215,7 @@ posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL", "POSIX-SYMLINK-EA", "POSIX-BLOCKING-LOCK", "POSIX-ACL-OPLOCK", "POSIX-ACL-SHAREROOT", + "POSIX-SYMLINK-ERRORCODE", ] for t in posix_tests: diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 38a9330cac7..ccb5b641d77 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -9500,6 +9500,301 @@ static bool run_posix_acl_shareroot_test(int dummy) return correct; } +/* + Ensure we get the same error code of + NT_STATUS_OBJECT_NAME_NOT_FOUND for dangling + symlinks, no matter where they point or how we + try and access them. + */ + +static bool run_posix_symlink_errorcode_test(int dummy) +{ + TALLOC_CTX *frame = NULL; + struct cli_state *cli_unix = NULL; + struct cli_state *cli_smb1_noposix = NULL; + struct cli_state *cli_smb2 = NULL; + NTSTATUS status; + struct stat statbuf; + bool correct = false; + size_t i; + int ret; + SMB_STRUCT_STAT sbuf; + uint16_t fnum_smb1 = (uint16_t)-1; + uint16_t fnum_smb2 = (uint16_t)-1; + const char *namearray_symlinks[3] = { + "nonexist_errorcode_symlink", + "tmp_symlink", + "tmp_noexist_symlink"}; + /* Can't use const herer as the third entry is dynamic. */ + char *namearray_target[3] = { + discard_const_p(char, "nonexist_errorcode_target"), + discard_const_p(char, "/tmp"), + NULL}; + + frame = talloc_stackframe(); + + printf("Starting POSIX-SYMLINK-ERRORCODE test\n"); + + /* Ensure /tmp exists. */ + ret = lstat("/tmp", &statbuf); + if (ret != 0) { + printf("lstat of /tmp failed error %s\n", + strerror(errno)); + TALLOC_FREE(frame); + return false; + } + /* + * Try 10 times to get a target name out of share we know doesn't exist. + */ + for (i = 0; i < 10; i++) { + namearray_target[2] = talloc_asprintf(talloc_tos(), + "/tmp/XXX%x%x", + (unsigned)i, + (unsigned)random()); + if (namearray_target[2] == NULL) { + TALLOC_FREE(frame); + return false; + } + ret = lstat(namearray_target[2], &statbuf); + if (ret == 0) { + TALLOC_FREE(namearray_target[2]); + continue; + } + if (ret != -1 && errno != ENOENT) { + TALLOC_FREE(namearray_target[2]); + continue; + } + break; + } + if (i == 10) { + printf("Can't find a temporary nonexistent name in /tmp\n"); + TALLOC_FREE(frame); + return false; + } + + /* Open an SMB1+POSIX connection. */ + if (!torture_open_connection(&cli_unix, 0)) { + printf("torture_open_connection SMB1+POSIX failed !\n"); + TALLOC_FREE(frame); + return false; + } + smbXcli_conn_set_sockopt(cli_unix->conn, sockops); + status = torture_setup_unix_extensions(cli_unix); + if (!NT_STATUS_IS_OK(status)) { + printf("torture_setup_unix_extensions failed !\n"); + TALLOC_FREE(frame); + return false; + } + + /* + * Start with a clean slate. + * Ensure + * "nonexist_errorcode_target" + * "nonexist_errorcode_symlink", + * "tmp_symlink", + * "tmp_noexist_symlink" + * don't exist. + */ + cli_posix_unlink(cli_unix, namearray_target[0]); + for (i = 0; i < ARRAY_SIZE(namearray_symlinks); i++) { + cli_posix_unlink(cli_unix, namearray_symlinks[i]); + } + + /* + * Create all 3 symlinks. + * 1). "nonexist_errorcode_symlink" -> "nonexist_errorcode_target". + * 2). "tmp_symlink" -> "/tmp" + * 3). "tmp_noexist_symlink" -> "/tmp/XXX". + */ + for (i = 0; i < ARRAY_SIZE(namearray_symlinks); i++) { + status = cli_posix_symlink(cli_unix, + namearray_target[i], + namearray_symlinks[i]); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_posix_symlink of %s -> %s failed " + "error %s\n", + namearray_symlinks[i], + namearray_target[i], + nt_errstr(status)); + goto out; + } + } + + /* We should be able to stat all 3. */ + for (i = 0; i < ARRAY_SIZE(namearray_symlinks); i++) { + status = cli_posix_stat(cli_unix, namearray_symlinks[i], &sbuf); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_posix_stat of %s failed error %s\n", + namearray_symlinks[i], + nt_errstr(status)); + goto out; + } + } + + /* + * But Opening all 3 via SMB1+POSIX should get + * NT_STATUS_OBJECT_NAME_NOT_FOUND. + */ + for (i = 0; i < ARRAY_SIZE(namearray_symlinks); i++) { + status = cli_posix_open(cli_unix, + namearray_symlinks[i], + O_RDONLY, + 0600, + &fnum_smb1); + if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + printf("cli_posix_open of %s got error %s " + "should be NT_STATUS_OBJECT_NAME_NOT_FOUND.\n", + namearray_symlinks[i], + nt_errstr(status)); + goto out; + } + } + + /* + * Opening all 3 via SMB1 without POSIX should also get + * NT_STATUS_OBJECT_NAME_NOT_FOUND. + */ + /* Open an SMB1 connection - without POSIX. */ + if (!torture_open_connection(&cli_smb1_noposix, 0)) { + printf("torture_open_connection SMB1 without POSIX failed !\n"); + TALLOC_FREE(frame); + return false; + } + for (i = 0; i < ARRAY_SIZE(namearray_symlinks); i++) { + status = cli_ntcreate(cli_smb1_noposix, /* cli. */ + namearray_symlinks[i], /* fname */ + 0, /* CreatFlags */ + READ_CONTROL_ACCESS, /* DesiredAccess */ + 0, /* FileAttributes */ + FILE_SHARE_READ| + FILE_SHARE_WRITE| + FILE_SHARE_DELETE, /* ShareAccess */ + FILE_OPEN, /* CreateDisposition */ + 0, /* CreateOptions */ + 0x0, /* SecurityFlags */ + &fnum_smb2, /* fnum. */ + NULL); /* cr */ + if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + printf("cli_ntcreate of %s got error %s " + "should be NT_STATUS_OBJECT_NAME_NOT_FOUND.\n", + namearray_symlinks[i], + nt_errstr(status)); + goto out; + } + } + /* + * Trying to do a cli_posix_stat() via SMB1 without POSIX should + * get NT_STATUS_INVALID_LEVEL. + */ + for (i = 0; i < ARRAY_SIZE(namearray_symlinks); i++) { + status = cli_posix_stat(cli_smb1_noposix, + namearray_symlinks[i], + &sbuf); + if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_LEVEL)) { + printf("cli_posix_stat of %s got error %s " + "should be NT_STATUS_INVALID_LEVEL.\n", + namearray_symlinks[i], + nt_errstr(status)); + goto out; + } + } + + /* Open an SMB2 connection. */ + if (!torture_init_connection(&cli_smb2)) { + printf("torture_init_connection for SMB2 failed\n"); + goto out; + } + + status = smbXcli_negprot(cli_smb2->conn, + cli_smb2->timeout, + PROTOCOL_SMB2_02, + PROTOCOL_SMB2_02); + if (!NT_STATUS_IS_OK(status)) { + printf("SMB2 smbXcli_negprot returned %s\n", + nt_errstr(status)); + goto out; + } + + status = cli_session_setup_creds(cli_smb2, torture_creds); + if (!NT_STATUS_IS_OK(status)) { + printf("SMB2 cli_session_setup returned %s\n", + nt_errstr(status)); + goto out; + } + + status = cli_tree_connect(cli_smb2, share, "?????", NULL); + if (!NT_STATUS_IS_OK(status)) { + printf("SMB2 cli_tree_connect returned %s\n", + nt_errstr(status)); + goto out; + } + + /* + * Opening all 3 via SMB2 should get + * NT_STATUS_OBJECT_NAME_NOT_FOUND. + */ + for (i = 0; i < ARRAY_SIZE(namearray_symlinks); i++) { + status = cli_ntcreate(cli_smb2, /* cli. */ + namearray_symlinks[i], /* fname */ + 0, /* CreatFlags */ + READ_CONTROL_ACCESS, /* DesiredAccess */ + 0, /* FileAttributes */ + FILE_SHARE_READ| + FILE_SHARE_WRITE| + FILE_SHARE_DELETE, /* ShareAccess */ + FILE_OPEN, /* CreateDisposition */ + 0, /* CreateOptions */ + 0x0, /* SecurityFlags */ + &fnum_smb2, /* fnum. */ + NULL); /* cr */ + if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + printf("cli_ntcreate of %s got error %s " + "should be NT_STATUS_OBJECT_NAME_NOT_FOUND.\n", + namearray_symlinks[i], + nt_errstr(status)); + goto out; + } + } + + printf("POSIX-SYMLINK-ERRORCODE test passed\n"); + correct = true; + +out: + if (fnum_smb1 != (uint16_t)-1) { + cli_close(cli_unix, fnum_smb1); + } + if (fnum_smb2 != (uint16_t)-1) { + cli_close(cli_smb2, fnum_smb2); + } + /* Ensure + * "nonexist_errorcode_target" + * "nonexist_errorcode_symlink", + * "tmp_symlink", + * "tmp_noexist_symlink" + * don't exist. + */ + cli_posix_unlink(cli_unix, namearray_target[0]); + for (i = 0; i < ARRAY_SIZE(namearray_symlinks); i++) { + cli_posix_unlink(cli_unix, namearray_symlinks[i]); + } + if (cli_unix != NULL) { + if (!torture_close_connection(cli_unix)) { + correct = false; + } + } + if (cli_smb1_noposix != NULL) { + if (!torture_close_connection(cli_smb1_noposix)) { + correct = false; + } + } + if (cli_smb2 != NULL) { + if (!torture_close_connection(cli_smb2)) { + correct = false; + } + } + TALLOC_FREE(frame); + return correct; +} static uint32_t open_attrs_table[] = { FILE_ATTRIBUTE_NORMAL, @@ -14615,6 +14910,11 @@ static struct { .name = "POSIX-ACL-SHAREROOT", .fn = run_posix_acl_shareroot_test, }, + { + .name = "POSIX-SYMLINK-ERRORCODE", + .fn = run_posix_symlink_errorcode_test, + }, + { .name = "WINDOWS-BAD-SYMLINK", .fn = run_symlink_open_test, @@ -14631,6 +14931,10 @@ static struct { .name = "UID-REGRESSION-TEST", .fn = run_uid_regression_test, }, + { + .name = "POSIX-SYMLINK-ERRORCODE", + .fn = run_posix_symlink_errorcode_test, + }, { .name = "SHORTNAME-TEST", .fn = run_shortname_test, -- 2.30.2 From 9c91b473c296b63e77a426687f4a00729463a256 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 00:15:03 -0800 Subject: [PATCH 13/16] CVE-2021-44141: s3: torture: Make simple POSIX test expect NT_STATUS_OBJECT_NAME_NOT_FOUND. Add to knownfail selftest/knownfail.d/posix_symlink_errorcode for now until we fix smbd. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_symlink_errorcode | 2 ++ source3/torture/torture.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/selftest/knownfail.d/posix_symlink_errorcode b/selftest/knownfail.d/posix_symlink_errorcode index e2e5d28be5c..013f85104c8 100644 --- a/selftest/knownfail.d/posix_symlink_errorcode +++ b/selftest/knownfail.d/posix_symlink_errorcode @@ -1,2 +1,4 @@ ^samba3.smbtorture_s3.plain.POSIX-SYMLINK-ERRORCODE.smbtorture\(nt4_dc_smb1\) ^samba3.smbtorture_s3.crypt.POSIX-SYMLINK-ERRORCODE.smbtorture\(nt4_dc_smb1\) +^samba3.smbtorture_s3.plain.POSIX.smbtorture\(nt4_dc_smb1\) +^samba3.smbtorture_s3.crypt.POSIX.smbtorture\(nt4_dc_smb1\) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index ccb5b641d77..eee493436f8 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -7917,10 +7917,10 @@ static bool run_simple_posix_open_test(int dummy) printf("POSIX open of %s succeeded (should have failed)\n", sname); goto out; } else { - if (!check_both_error(__LINE__, status, ERRDOS, ERRbadpath, - NT_STATUS_OBJECT_PATH_NOT_FOUND)) { + if (!check_both_error(__LINE__, status, ERRDOS, ERRbadfile, + NT_STATUS_OBJECT_NAME_NOT_FOUND)) { printf("POSIX open of %s should have failed " - "with NT_STATUS_OBJECT_PATH_NOT_FOUND, " + "with NT_STATUS_OBJECT_NAME_NOT_FOUND, " "failed with %s instead.\n", sname, nt_errstr(status)); goto out; -- 2.30.2 From 6199e72d9a953b5cc7887a247cd7eb794458df32 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 10:22:10 -0800 Subject: [PATCH 14/16] CVE-2021-44141: s3: tests: Get test_smbclient_s3.sh ready for change in error return for symlinks (NT_STATUS_ACCESS_DENIED -> NT_STATUS_OBJECT_NAME_NOT_FOUND). Add to selftest/knownfail.d/posix_symlink_errorcode. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_symlink_errorcode | 2 ++ source3/script/tests/test_smbclient_s3.sh | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/selftest/knownfail.d/posix_symlink_errorcode b/selftest/knownfail.d/posix_symlink_errorcode index 013f85104c8..00448349c30 100644 --- a/selftest/knownfail.d/posix_symlink_errorcode +++ b/selftest/knownfail.d/posix_symlink_errorcode @@ -2,3 +2,5 @@ ^samba3.smbtorture_s3.crypt.POSIX-SYMLINK-ERRORCODE.smbtorture\(nt4_dc_smb1\) ^samba3.smbtorture_s3.plain.POSIX.smbtorture\(nt4_dc_smb1\) ^samba3.smbtorture_s3.crypt.POSIX.smbtorture\(nt4_dc_smb1\) +^samba3.blackbox.smbclient_s3.*Ensure\ widelinks\ are\ restricted.* +^samba3.blackbox.smbclient_s3.*follow\ symlinks\ =\ no.* diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh index 62662690415..165d1d0ff81 100755 --- a/source3/script/tests/test_smbclient_s3.sh +++ b/source3/script/tests/test_smbclient_s3.sh @@ -1010,12 +1010,12 @@ EOF return 1 fi -# This should fail with NT_STATUS_ACCESS_DENIED - echo "$out" | grep 'NT_STATUS_ACCESS_DENIED' +# This should fail with NT_STATUS_OBJECT_NAME_NOT_FOUND + echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND' ret=$? if [ $ret != 0 ] ; then echo "$out" - echo "failed - should get NT_STATUS_ACCESS_DENIED listing \\widelinks_share\\source" + echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND listing \\widelinks_share\\source" return 1 fi } @@ -1133,11 +1133,11 @@ EOF return 1 fi - echo "$out" | grep 'NT_STATUS_ACCESS_DENIED' + echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND' ret=$? if [ $ret -ne 0 ] ; then echo "$out" - echo "failed - should get NT_STATUS_ACCESS_DENIED getting \\nosymlinks\\source" + echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND getting \\nosymlinks\\source" return 1 fi -- 2.30.2 From 22e73f68554ec0a2b505d6e6fa11561597a0b421 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 10:40:58 -0800 Subject: [PATCH 15/16] CVE-2021-44141: s3: smbd: In check_reduced_name() and check_reduced_name_with_privilege(), return NT_STATUS_OBJECT_NAME_NOT_FOUND instead of NT_STATUS_ACCESS_DENIED for symlinks we cannot reach. They are either out of share or point to nowhere. Always match the symlink error returned by openat_pathref_fsp(). This unifies the return for symlinks over SMB1, SMB1+POSIX and SMB2 when parsing a path and lays the foundation for SMB2+POSIX. Remove knownfails in selftest/knownfail.d/posix_symlink_errorcode for test_smbclient_s3.sh. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_symlink_errorcode | 2 -- source3/smbd/vfs.c | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/selftest/knownfail.d/posix_symlink_errorcode b/selftest/knownfail.d/posix_symlink_errorcode index 00448349c30..013f85104c8 100644 --- a/selftest/knownfail.d/posix_symlink_errorcode +++ b/selftest/knownfail.d/posix_symlink_errorcode @@ -2,5 +2,3 @@ ^samba3.smbtorture_s3.crypt.POSIX-SYMLINK-ERRORCODE.smbtorture\(nt4_dc_smb1\) ^samba3.smbtorture_s3.plain.POSIX.smbtorture\(nt4_dc_smb1\) ^samba3.smbtorture_s3.crypt.POSIX.smbtorture\(nt4_dc_smb1\) -^samba3.blackbox.smbclient_s3.*Ensure\ widelinks\ are\ restricted.* -^samba3.blackbox.smbclient_s3.*follow\ symlinks\ =\ no.* diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index c4978fe5212..4445539a529 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1218,7 +1218,7 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, DBG_ERR("device/inode/uid/gid on directory %s changed. " "Denying access !\n", smb_fname_str_dbg(parent_name)); - status = NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto err; } @@ -1255,7 +1255,7 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, smb_fname_str_dbg(parent_name)); DEBUGADD(1, ("conn_rootdir =%s\n", conn_rootdir)); DEBUGADD(1, ("resolved_name=%s\n", resolved_name)); - status = NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto err; } } @@ -1281,7 +1281,7 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, DBG_WARNING("Last component %s is a symlink. Denying" "access.\n", smb_fname_str_dbg(file_name)); - status = NT_STATUS_ACCESS_DENIED; + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; goto err; } @@ -1431,7 +1431,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, conn_rootdir, resolved_name); TALLOC_FREE(resolved_fname); - return NT_STATUS_ACCESS_DENIED; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } } @@ -1455,7 +1455,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, *p, fname); TALLOC_FREE(resolved_fname); - return NT_STATUS_ACCESS_DENIED; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } p++; @@ -1486,7 +1486,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, p); TALLOC_FREE(resolved_fname); TALLOC_FREE(new_fname); - return NT_STATUS_ACCESS_DENIED; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } } -- 2.30.2 From 0eb6b91227a99c96711f86d7913369c3d26ea7a9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 10:55:15 -0800 Subject: [PATCH 16/16] CVE-2021-44141: s3: smbd: For SMB1+POSIX clients trying to open a symlink, always return NT_STATUS_OBJECT_NAME_NOT_FOUND. Matches the error return from openat_pathref_fsp(). NT_STATUS_OBJECT_PATH_NOT_FOUND is for a bad component in a path, not a bad terminal symlink. Now all symlink errors are returned as NT_STATUS_OBJECT_NAME_NOT_FOUND for both SMB1, SMB1+POSIX and SMB2+. Remove knownfail file selftest/knownfail.d/posix_symlink_errorcode. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_symlink_errorcode | 4 --- source3/smbd/open.c | 27 +++++++++++++++++--- 2 files changed, 24 insertions(+), 7 deletions(-) delete mode 100644 selftest/knownfail.d/posix_symlink_errorcode diff --git a/selftest/knownfail.d/posix_symlink_errorcode b/selftest/knownfail.d/posix_symlink_errorcode deleted file mode 100644 index 013f85104c8..00000000000 --- a/selftest/knownfail.d/posix_symlink_errorcode +++ /dev/null @@ -1,4 +0,0 @@ -^samba3.smbtorture_s3.plain.POSIX-SYMLINK-ERRORCODE.smbtorture\(nt4_dc_smb1\) -^samba3.smbtorture_s3.crypt.POSIX-SYMLINK-ERRORCODE.smbtorture\(nt4_dc_smb1\) -^samba3.smbtorture_s3.plain.POSIX.smbtorture\(nt4_dc_smb1\) -^samba3.smbtorture_s3.crypt.POSIX.smbtorture\(nt4_dc_smb1\) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 0c2c381bde5..32788097978 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -502,7 +502,8 @@ static int process_symlink_open(struct connection_struct *conn, */ link_depth++; if (link_depth >= 20) { - errno = ELOOP; + /* We want this to map to NT_STATUS_OBJECT_NAME_NOT_FOUND */ + errno = ENOENT; goto out; } @@ -553,7 +554,8 @@ static int process_symlink_open(struct connection_struct *conn, resolved_name, rootdir_len) == 0); if (!matched) { - errno = EACCES; + /* We want this to map to NT_STATUS_OBJECT_NAME_NOT_FOUND */ + errno = ENOENT; goto out; } @@ -569,7 +571,8 @@ static int process_symlink_open(struct connection_struct *conn, smb_fname->base_name = talloc_strdup(smb_fname, &resolved_name[rootdir_len+1]); } else { - errno = EACCES; + /* We want this to map to NT_STATUS_OBJECT_NAME_NOT_FOUND */ + errno = ENOENT; goto out; } @@ -721,10 +724,28 @@ static int non_widelink_open(files_struct *fsp, if (saved_errno == ELOOP || saved_errno == ENOTDIR) { if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) { /* Never follow symlinks on posix open. */ + /* + * map_nt_error_from_unix() maps ELOOP to + * NT_STATUS_OBJECT_PATH_NOT_FOUND. For + * error return consistency we need this + * to map to NT_STATUS_OBJECT_NAME_NOT_FOUND. + * + * https://bugzilla.samba.org/show_bug.cgi?id=14911 + */ + saved_errno = ENOENT; goto out; } if (!lp_follow_symlinks(SNUM(conn))) { /* Explicitly no symlinks. */ + /* + * map_nt_error_from_unix() maps ELOOP to + * NT_STATUS_OBJECT_PATH_NOT_FOUND. For + * error return consistency we need this + * to map to NT_STATUS_OBJECT_NAME_NOT_FOUND. + * + * https://bugzilla.samba.org/show_bug.cgi?id=14911 + */ + saved_errno = ENOENT; goto out; } /* -- 2.30.2