From 60aedc8a7b33b66aa9ba8a12e61de2a33cb5405b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 12:54:47 -0800 Subject: [PATCH 01/16] s4: torture: Fix raw.search:test_one_file() to use torture_result() instead of printf. I think this test pre-dates torture_result. 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 14af01bffad..07285893f40 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -316,7 +316,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; } @@ -343,9 +347,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; } @@ -363,7 +369,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)); @@ -400,8 +408,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; \ @@ -412,8 +422,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; \ @@ -424,8 +436,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; \ @@ -436,8 +450,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; \ @@ -450,8 +466,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; \ @@ -464,8 +482,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; \ @@ -477,8 +497,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 e979023f012921f73a02021340c52d1669ca2561 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 14:18:47 -0800 Subject: [PATCH 02/16] 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). 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 07285893f40..9b140928689 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -305,8 +305,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; @@ -581,20 +581,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 e2792a4f08debbb5b356a65bd4a7119d9b327307 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 18 Nov 2021 11:48:42 -0800 Subject: [PATCH 03/16] 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.* Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_infolevel_fails | 8 +++ source3/smbd/trans2.c | 60 +++++++++++++++++++--- 2 files changed, 62 insertions(+), 6 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 5f763d4ab4d..361901ce075 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -2719,6 +2719,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; + } break; default: reply_nterror(req, NT_STATUS_INVALID_LEVEL); @@ -3273,6 +3277,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); @@ -5237,8 +5245,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", @@ -6051,9 +6064,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. */ @@ -6146,6 +6165,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 (req->posix_pathnames) { @@ -9174,7 +9197,9 @@ NTSTATUS smbd_do_setfilepathinfo(connection_struct *conn, if (!lp_unix_extensions()) { return NT_STATUS_INVALID_LEVEL; } - + if (!req->posix_pathnames) { + return NT_STATUS_INVALID_LEVEL; + } status = smbd_do_posix_setfilepathinfo(conn, req, req, @@ -9395,6 +9420,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 = fsp->fsp_name; if (fsp_get_pathref_fd(fsp) == -1) { @@ -9473,6 +9509,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 c707a0c8d4fd2eb42f485f120c1cd2f246288ce2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Sat, 20 Nov 2021 20:17:11 -0800 Subject: [PATCH 04/16] 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. 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 a45215a7795..7ea9f4f96aa 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -2815,6 +2815,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, "", @@ -2876,6 +2881,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, "", @@ -2910,6 +2920,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(), @@ -2955,6 +2970,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(), @@ -3154,6 +3174,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); @@ -3190,6 +3216,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); @@ -3213,6 +3245,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, @@ -3350,6 +3388,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", @@ -3403,6 +3447,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", @@ -3442,6 +3492,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) { @@ -3525,6 +3580,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", @@ -3689,6 +3750,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)) { @@ -3988,6 +4055,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", @@ -4102,6 +4175,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 889c225d36aeb8820e96074118d3ebf1c5b781a5 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 14:44:05 -0800 Subject: [PATCH 05/16] 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. 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 9b140928689..f6ad569dd4b 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -300,8 +300,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; @@ -1571,7 +1572,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 de0fa6c3841a7faeb54c8b10c49bdee5f8a65f0a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 14:48:20 -0800 Subject: [PATCH 06/16] s4: torture: raw.search: Add setup_smb1_posix(). Call it on the second connection in test_one_file(). Not yet used. 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 f6ad569dd4b..3f7de80ad0f 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -297,6 +297,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 */ @@ -315,6 +364,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 4ceb402b14059b25c34c74ae9f2f8b894928bea8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 14:51:39 -0800 Subject: [PATCH 07/16] 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 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 3f7de80ad0f..575bbd03fb7 100644 --- a/source4/torture/raw/search.c +++ b/source4/torture/raw/search.c @@ -389,10 +389,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, @@ -416,7 +425,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 0b714f508147784e3613040a3a56a7e92f275a61 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 12:15:06 -0800 Subject: [PATCH 08/16] 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\) 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 6b275435551..2098b225e7f 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/cmdline.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 5882f7d071299d0cf489a81c92a612ff55200271 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 12:12:36 -0800 Subject: [PATCH 09/16] 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.* 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 4beb7b9bb503b2431fda4f66cfbcce77d75c95e3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 00:05:35 -0800 Subject: [PATCH 10/16] 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.* 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 5767b97f9e14a408d71ac595767026e1131cd9b3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 18 Nov 2021 12:16:44 -0800 Subject: [PATCH 11/16] 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. 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 8cfa05dd5c2..fc57655739e 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -8911,6 +8911,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 114e3637bfdfd3830a1b1c34f0636cc06fe96c57 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 18 Nov 2021 16:57:18 -0800 Subject: [PATCH 12/16] 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. Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_symlink_errorcode | 2 + source3/selftest/tests.py | 1 + source3/torture/proto.h | 1 + source3/torture/test_posix.c | 300 +++++++++++++++++++ source3/torture/torture.c | 4 + 5 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/source3/selftest/tests.py b/source3/selftest/tests.py index f4319959353..af2be90040e 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -299,6 +299,7 @@ posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL", "POSIX-SYMLINK-EA", "POSIX-SYMLINK-RENAME", "POSIX-SYMLINK-GETPATHINFO", "POSIX-SYMLINK-SETPATHINFO", + "POSIX-SYMLINK-ERRORCODE", ] for t in posix_tests: diff --git a/source3/torture/proto.h b/source3/torture/proto.h index 65fa17523d8..00583e9926a 100644 --- a/source3/torture/proto.h +++ b/source3/torture/proto.h @@ -96,6 +96,7 @@ bool run_case_insensitive_create(int dummy); bool run_posix_symlink_rename_test(int dummy); bool run_posix_symlink_getpathinfo_test(int dummy); bool run_posix_symlink_setpathinfo_test(int dummy); +bool run_posix_symlink_errorcode_test(int dummy); bool run_nbench2(int dummy); bool run_async_echo(int dummy); diff --git a/source3/torture/test_posix.c b/source3/torture/test_posix.c index 20b2b136761..c7bb9be821a 100644 --- a/source3/torture/test_posix.c +++ b/source3/torture/test_posix.c @@ -1888,3 +1888,303 @@ out: TALLOC_FREE(frame); 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. + */ + +/* Needed for SMB2 connection. */ +extern fstring host, workgroup, share, password, username, myname; +extern struct cli_credentials *torture_creds; + +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; + } + torture_conn_set_sockopt(cli_unix); + 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; +} diff --git a/source3/torture/torture.c b/source3/torture/torture.c index fc57655739e..faaf2c58bcf 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -15021,6 +15021,10 @@ static struct { .name = "POSIX-SYMLINK-SETPATHINFO", .fn = run_posix_symlink_setpathinfo_test, }, + { + .name = "POSIX-SYMLINK-ERRORCODE", + .fn = run_posix_symlink_errorcode_test, + }, { .name = "WINDOWS-BAD-SYMLINK", .fn = run_symlink_open_test, -- 2.30.2 From 780af56caa79d1e89b2cd2d9ee16d2672f9d753e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 00:15:03 -0800 Subject: [PATCH 13/16] 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. 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 faaf2c58bcf..f71ba4b49e9 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -7965,10 +7965,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 58fa9462768eafdcd4bcc53c8dfe0eba185341dc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 10:22:10 -0800 Subject: [PATCH 14/16] 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. 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 89a17656159..e250d4dd106 100755 --- a/source3/script/tests/test_smbclient_s3.sh +++ b/source3/script/tests/test_smbclient_s3.sh @@ -1044,12 +1044,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 } @@ -1168,11 +1168,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 764bd5a6a1c06cc53b6ffde92a4bb23f5bc8a442 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 10:40:58 -0800 Subject: [PATCH 15/16] 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. 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 570de843811..296fde95532 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1215,7 +1215,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; } @@ -1252,7 +1252,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; } } @@ -1278,7 +1278,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; } @@ -1429,7 +1429,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; } } @@ -1453,7 +1453,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++; @@ -1484,7 +1484,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 ce1eac499e6a706557ea242929a829de10edf6a6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 19 Nov 2021 10:55:15 -0800 Subject: [PATCH 16/16] 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. Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_symlink_errorcode | 4 ---- source3/smbd/open.c | 13 ++++++------- 2 files changed, 6 insertions(+), 11 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 7f1aedbd1fb..753c0f56ada 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1448,12 +1448,10 @@ static NTSTATUS open_file(files_struct *fsp, * POSIX client that hit a symlink. We don't want to * return NT_STATUS_STOPPED_ON_SYMLINK to avoid handling * this special error code in all callers, so we map - * this to NT_STATUS_OBJECT_PATH_NOT_FOUND. Historically - * the lower level functions returned status code mapped - * from errno by map_nt_error_from_unix() where ELOOP is - * mapped to NT_STATUS_OBJECT_PATH_NOT_FOUND. + * this to NT_STATUS_OBJECT_NAME_NOT_FOUND to match + * openat_pathref_fsp(). */ - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " @@ -1536,9 +1534,10 @@ static NTSTATUS open_file(files_struct *fsp, { /* * Don't allow stat opens on symlinks directly unless - * it's a POSIX open. + * it's a POSIX open. Match the return code from + * openat_pathref_fsp(). */ - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (!fsp->fsp_flags.is_pathref) { -- 2.30.2