From ac9740a0966c42ce08e92737fa0b8e476cdd490b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 9 Jul 2019 12:03:38 +0200 Subject: [PATCH 001/376] VERSION: Bump version up to 4.11.0rc2... and re-enable GIT_SNAPSHOT. Signed-off-by: Stefan Metzmacher --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index e9931834e6c..c70b521219c 100644 --- a/VERSION +++ b/VERSION @@ -87,7 +87,7 @@ SAMBA_VERSION_PRE_RELEASE= # e.g. SAMBA_VERSION_RC_RELEASE=1 # # -> "3.0.0rc1" # ######################################################## -SAMBA_VERSION_RC_RELEASE=1 +SAMBA_VERSION_RC_RELEASE=2 ######################################################## # To mark SVN snapshots this should be set to 'yes' # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE=1 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname # -- 2.17.1 From 1c64a2e37b695fcae9f64dea6f82c6fcadc990c4 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 9 Jul 2019 12:21:10 +0200 Subject: [PATCH 002/376] WHATSNEW: preview release -> release candidate Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index c0d13d20d6b..b07e9eba778 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,7 +1,7 @@ Release Announcements ===================== -This is the first preview release of Samba 4.11. This is *not* +This is the second release candidate of Samba 4.11. This is *not* intended for production environments and is designed for testing purposes only. Please report any defects via the Samba bug reporting system at https://bugzilla.samba.org/. -- 2.17.1 From 6877eabea8f34e49b2ccec3ac1793600b8a0475e Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Thu, 11 Jul 2019 17:12:06 +1200 Subject: [PATCH 003/376] partition: correcting lock ordering A schema reading bug was traced to a lock ordering issue in partition.c. This patch fixes the problem by: 1. Releasing locks/transactions in the order they were acquired. 2. Always lock/start_trans on metadata.tdb first, before any other databases, and release it last, after all others. This is so that we are never exposed to MDB's lock semantics, which we don't support. Signed-off-by: Aaron Haslett Reviewed-by: Garming Sam Reviewed-by: Andrew Bartlett (cherry picked from commit 7f4bc0ea81f2b34607849911f1271b030be8ca02) --- source4/dsdb/samdb/ldb_modules/partition.c | 135 +++++++++++++-------- 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index 4cfcf6f3ba7..93fa129c14e 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -1032,8 +1032,8 @@ static int partition_rename(struct ldb_module *module, struct ldb_request *req) /* start a transaction */ int partition_start_trans(struct ldb_module *module) { - int i; - int ret; + int i = 0; + int ret = 0; struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module), struct partition_private_data); /* Look at base DN */ @@ -1043,18 +1043,58 @@ int partition_start_trans(struct ldb_module *module) ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_start_trans() -> (metadata partition)"); } - /* This order must match that in prepare_commit() and read_lock() */ + /* + * We start a transaction on metadata.tdb first and end it last in + * end_trans. This makes locking semantics follow TDB rather than MDB, + * and effectively locks all partitions at once. + * Detail: + * Samba AD is special in that the partitions module (this file) + * combines multiple independently locked databases into one overall + * transaction. Changes across multiple partition DBs in a single + * transaction must ALL be either visible or invisible. + * The way this is achieved is by taking out a write lock on + * metadata.tdb at the start of prepare_commit, while unlocking it at + * the end of end_trans. This is matched by read_lock, ensuring it + * can't progress until that write lock is released. + * + * metadata.tdb needs to be a TDB file because MDB uses independent + * locks, which means a read lock and a write lock can be held at the + * same time, whereas in TDB, the two locks block each other. The TDB + * behaviour is required to implement the functionality described + * above. + * + * An important additional detail here is that if prepare_commit is + * called on a TDB without any changes being made, no write lock is + * taken. We address this by storing a sequence number in metadata.tdb + * which is updated every time a replicated attribute is modified. + * The possibility of a few unreplicated attributes being out of date + * turns out not to be a problem. + * For this reason, a lock on sam.ldb (which is a TDB) won't achieve + * the same end as locking metadata.tdb, unless we made a modification + * to the @ records found there before every prepare_commit. + */ + ret = partition_metadata_start_trans(module); + if (ret != LDB_SUCCESS) { + return ret; + } + ret = ldb_next_start_trans(module); if (ret != LDB_SUCCESS) { + partition_metadata_del_trans(module); return ret; } ret = partition_reload_if_required(module, data, NULL); if (ret != LDB_SUCCESS) { ldb_next_del_trans(module); + partition_metadata_del_trans(module); return ret; } + /* + * The following per partition locks are required mostly because TDB + * and MDB require locks before read and write ops are permitted. + */ for (i=0; data && data->partitions && data->partitions[i]; i++) { if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_start_trans() -> %s", @@ -1072,20 +1112,6 @@ int partition_start_trans(struct ldb_module *module) } } - /* - * Because in prepare_commit this must come last, to ensure - * lock ordering we have to do this last here also - */ - ret = partition_metadata_start_trans(module); - if (ret != LDB_SUCCESS) { - /* Back it out, if it fails on one */ - for (i--; i >= 0; i--) { - ldb_next_del_trans(data->partitions[i]->module); - } - ldb_next_del_trans(module); - return ret; - } - data->in_transaction++; return LDB_SUCCESS; @@ -1099,6 +1125,15 @@ int partition_prepare_commit(struct ldb_module *module) struct partition_private_data); int ret; + /* + * Order of prepare_commit calls must match that in + * partition_start_trans. See comment in that function for detail. + */ + ret = partition_metadata_prepare_commit(module); + if (ret != LDB_SUCCESS) { + return ret; + } + ret = ldb_next_prepare_commit(module); if (ret != LDB_SUCCESS) { return ret; @@ -1122,9 +1157,7 @@ int partition_prepare_commit(struct ldb_module *module) ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_prepare_commit() -> (metadata partition)"); } - /* metadata prepare commit must come last, as other partitions could modify - * the database inside the prepare commit method of a module */ - return partition_metadata_prepare_commit(module); + return LDB_SUCCESS; } @@ -1145,7 +1178,10 @@ int partition_end_trans(struct ldb_module *module) data->in_transaction--; } - + /* + * Order of end_trans calls must be the reverse of that in + * partition_start_trans. See comment in that function for detail. + */ for (i=0; data && data->partitions && data->partitions[i]; i++) { if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_end_trans() -> %s", @@ -1184,6 +1220,10 @@ int partition_del_trans(struct ldb_module *module) struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module), struct partition_private_data); + /* + * Order of del_trans calls must be the reverse of that in + * partition_start_trans. See comment in that function for detail. + */ for (i=0; data && data->partitions && data->partitions[i]; i++) { if (ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING) { @@ -1382,9 +1422,9 @@ static int partition_sequence_number(struct ldb_module *module, struct ldb_reque /* lock all the backends */ int partition_read_lock(struct ldb_module *module) { - int i; - int ret; - int ret2; + int i = 0; + int ret = 0; + int ret2 = 0; struct ldb_context *ldb = ldb_module_get_ctx(module); struct partition_private_data *data = \ talloc_get_type(ldb_module_get_private(module), @@ -1430,9 +1470,8 @@ int partition_read_lock(struct ldb_module *module) } /* - * This will lock the metadata partition (sam.ldb) and - * will also call event loops, so we do it before we - * get the whole db lock. + * This will lock sam.ldb and will also call event loops, + * so we do it before we get the whole db lock. */ ret = partition_reload_if_required(module, data, NULL); if (ret != LDB_SUCCESS) { @@ -1440,8 +1479,20 @@ int partition_read_lock(struct ldb_module *module) } /* - * This order must match that in prepare_commit(), start with - * the top level DB (sam.ldb) lock + * Order of read_lock calls must match that in partition_start_trans. + * See comment in that function for detail. + */ + ret = partition_metadata_read_lock(module); + if (ret != LDB_SUCCESS) { + goto failed; + } + + /* + * The top level DB (sam.ldb) lock is not enough to block another + * process in prepare_commit(), because if nothing was changed in the + * specific backend, then prepare_commit() is a no-op. Therefore the + * metadata.tdb lock is taken out above, as it is the best we can do + * right now. */ ret = ldb_next_read_lock(module); if (ret != LDB_SUCCESS) { @@ -1455,12 +1506,8 @@ int partition_read_lock(struct ldb_module *module) } /* - * The top level DB (sam.ldb) lock is not - * enough to block another process in prepare_commit(), - * because prepare_commit() is a no-op, if nothing - * was changed in the specific backend. - * - * That means the following per partition locks are required. + * The following per partition locks are required mostly because TDB + * and MDB require locks before reads are permitted. */ for (i=0; data && data->partitions && data->partitions[i]; i++) { if ((module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING)) { @@ -1485,15 +1532,6 @@ int partition_read_lock(struct ldb_module *module) goto failed; } - /* - * Because in prepare_commit this must come last, to ensure - * lock ordering we have to do this last here also - */ - ret = partition_metadata_read_lock(module); - if (ret != LDB_SUCCESS) { - goto failed; - } - return LDB_SUCCESS; failed: @@ -1531,10 +1569,9 @@ int partition_read_unlock(struct ldb_module *module) struct partition_private_data); /* - * This order must be similar to partition_{end,del}_trans() - * the metadata partition (sam.ldb) unlock must be at the end. + * Order of read_unlock calls must be the reverse of that in + * partition_start_trans. See comment in that function for detail. */ - for (i=0; data && data->partitions && data->partitions[i]; i++) { if ((module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING)) { ldb_debug(ldb, LDB_DEBUG_TRACE, @@ -1584,10 +1621,6 @@ int partition_read_unlock(struct ldb_module *module) } } - /* - * Because in prepare_commit this must come last, to ensure - * lock ordering we have to do this last here also - */ ret = partition_metadata_read_unlock(module); /* -- 2.17.1 From 29fa37b717cc83080ed9eb50345370b8f40d7ce7 Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Mon, 15 Jul 2019 13:32:41 +1200 Subject: [PATCH 004/376] partition: reversing partition unlocking Unlock partition databases in the reverse order from which they were acquired. This is separated from the previous commit for future bisecting purposes, since the last commit was made to fix specific CI failures, while this one is a speculative fix made based on code inspection. Signed-off-by: Aaron Haslett Reviewed-by: Garming Sam Reviewed-by: Andrew Bartlett (cherry picked from commit 6c691bf84e41b1edd3228c219f7a94e108795d28) --- source4/dsdb/samdb/ldb_modules/partition.c | 125 ++++++++++++--------- 1 file changed, 72 insertions(+), 53 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index 93fa129c14e..e34ba35680b 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -1165,9 +1165,11 @@ int partition_prepare_commit(struct ldb_module *module) int partition_end_trans(struct ldb_module *module) { int ret, ret2; - unsigned int i; + int i; + struct ldb_context *ldb = ldb_module_get_ctx(module); struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module), struct partition_private_data); + bool trace = module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING; ret = LDB_SUCCESS; @@ -1182,21 +1184,28 @@ int partition_end_trans(struct ldb_module *module) * Order of end_trans calls must be the reverse of that in * partition_start_trans. See comment in that function for detail. */ - for (i=0; data && data->partitions && data->partitions[i]; i++) { - if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) { - ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_end_trans() -> %s", - ldb_dn_get_linearized(data->partitions[i]->ctrl->dn)); - } - ret2 = ldb_next_end_trans(data->partitions[i]->module); - if (ret2 != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb_module_get_ctx(module), "end_trans error on %s: %s", - ldb_dn_get_linearized(data->partitions[i]->ctrl->dn), - ldb_errstring(ldb_module_get_ctx(module))); - ret = ret2; + if (data && data->partitions) { + for (i=0; data->partitions[i]; i++);; + for (i--; i>=0; i--) { + struct dsdb_partition *p = data->partitions[i]; + if (trace) { + ldb_debug(ldb, + LDB_DEBUG_TRACE, + "partition_end_trans() -> %s", + ldb_dn_get_linearized(p->ctrl->dn)); + } + ret2 = ldb_next_end_trans(p->module); + if (ret2 != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "end_trans error on %s: %s", + ldb_dn_get_linearized(p->ctrl->dn), + ldb_errstring(ldb)); + ret = ret2; + } } } - if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) { + if (trace) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_end_trans() -> (metadata partition)"); } ret2 = ldb_next_end_trans(module); @@ -1216,31 +1225,38 @@ int partition_end_trans(struct ldb_module *module) int partition_del_trans(struct ldb_module *module) { int ret, final_ret = LDB_SUCCESS; - unsigned int i; + int i; + struct ldb_context *ldb = ldb_module_get_ctx(module); struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module), struct partition_private_data); + bool trace = module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING; /* * Order of del_trans calls must be the reverse of that in * partition_start_trans. See comment in that function for detail. */ - for (i=0; data && data->partitions && data->partitions[i]; i++) { - if (ldb_module_flags(ldb_module_get_ctx(module)) & - LDB_FLG_ENABLE_TRACING) { - ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_del_trans() -> %s", - ldb_dn_get_linearized(data->partitions[i]->ctrl->dn)); - } - ret = ldb_next_del_trans(data->partitions[i]->module); - if (ret != LDB_SUCCESS) { - ldb_asprintf_errstring(ldb_module_get_ctx(module), "del_trans error on %s: %s", - ldb_dn_get_linearized(data->partitions[i]->ctrl->dn), - ldb_errstring(ldb_module_get_ctx(module))); - final_ret = ret; + if (data && data->partitions) { + for (i=0; data->partitions[i]; i++);; + for (i--; i>=0; i--) { + struct dsdb_partition *p = data->partitions[i]; + if (trace) { + ldb_debug(ldb, + LDB_DEBUG_TRACE, + "partition_del_trans() -> %s", + ldb_dn_get_linearized(p->ctrl->dn)); + } + ret = ldb_next_del_trans(p->module); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, + "del_trans error on %s: %s", + ldb_dn_get_linearized(p->ctrl->dn), + ldb_errstring(ldb)); + final_ret = ret; + } } - } + } - if (ldb_module_flags(ldb_module_get_ctx(module)) & - LDB_FLG_ENABLE_TRACING) { + if (trace) { ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_del_trans() -> (metadata partition)"); } ret = ldb_next_del_trans(module); @@ -1567,39 +1583,42 @@ int partition_read_unlock(struct ldb_module *module) struct partition_private_data *data = \ talloc_get_type(ldb_module_get_private(module), struct partition_private_data); + bool trace = module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING; /* * Order of read_unlock calls must be the reverse of that in * partition_start_trans. See comment in that function for detail. */ - for (i=0; data && data->partitions && data->partitions[i]; i++) { - if ((module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING)) { - ldb_debug(ldb, LDB_DEBUG_TRACE, - "partition_read_unlock() -> %s", - ldb_dn_get_linearized( - data->partitions[i]->ctrl->dn)); - } - ret2 = ldb_next_read_unlock(data->partitions[i]->module); - if (ret2 != LDB_SUCCESS) { - ldb_debug_set(ldb, - LDB_DEBUG_FATAL, - "Failed to lock db: %s / %s for %s", - ldb_errstring(ldb), - ldb_strerror(ret), - ldb_dn_get_linearized( - data->partitions[i]->ctrl->dn)); - - /* - * Don't overwrite the original failure code - * if there was one - */ - if (ret == LDB_SUCCESS) { - ret = ret2; + if (data && data->partitions) { + for (i=0; data->partitions[i]; i++);; + for (i--; i>=0; i--) { + struct dsdb_partition *p = data->partitions[i]; + if (trace) { + ldb_debug(ldb, LDB_DEBUG_TRACE, + "partition_read_unlock() -> %s", + ldb_dn_get_linearized(p->ctrl->dn)); + } + ret2 = ldb_next_read_unlock(p->module); + if (ret2 != LDB_SUCCESS) { + ldb_debug_set(ldb, + LDB_DEBUG_FATAL, + "Failed to lock db: %s / %s for %s", + ldb_errstring(ldb), + ldb_strerror(ret), + ldb_dn_get_linearized(p->ctrl->dn)); + + /* + * Don't overwrite the original failure code + * if there was one + */ + if (ret == LDB_SUCCESS) { + ret = ret2; + } } } } - if (ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING) { + if (trace) { ldb_debug(ldb, LDB_DEBUG_TRACE, "partition_read_unlock() -> (metadata partition)"); } -- 2.17.1 From f2c40f4d41a4729bf31534ce34261d70c5dd0071 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Thu, 18 Jul 2019 14:50:57 +1200 Subject: [PATCH 005/376] gp_inf: Read/write files with a UTF-16LE BOM in GptTmpl.inf Regression caused by 16596842a62bec0a9d974c48d64000e3c079254e [MS-GPSB] 2.2 Message Syntax says that you have to write a BOM which I didn't do up until this patch. UTF-16 as input encoding was marked much higher up in the inheritance tree, which got overriden with the Python 3 fixes. I've now marked the encoding much more obviously for this file. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14004 Signed-off-by: Garming Sam Reviewed-by: Gary Lockyer Autobuild-User(master): Gary Lockyer Autobuild-Date(master): Fri Jul 19 02:20:47 UTC 2019 on sn-devel-184 (cherry picked from commit 0bcfc550b1a902e3a6a766b06603ac9285d0ff63) --- python/samba/gp_parse/gp_inf.py | 9 ++++++--- .../SecEdit/GptTmpl.inf.SAMBABACKUP | Bin 2580 -> 2582 bytes 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/python/samba/gp_parse/gp_inf.py b/python/samba/gp_parse/gp_inf.py index 79e28159f1f..a3c828fa82d 100644 --- a/python/samba/gp_parse/gp_inf.py +++ b/python/samba/gp_parse/gp_inf.py @@ -29,11 +29,11 @@ from samba.gp_parse import GPParser # [MS-GPSB] Security Protocol Extension class GptTmplInfParser(GPParser): sections = None - encoding = 'utf-16le' + encoding = 'utf-16' + output_encoding = 'utf-16le' class AbstractParam: __metaclass__ = ABCMeta - encoding = 'utf-16le' def __init__(self): self.param_list = [] @@ -333,7 +333,10 @@ class GptTmplInfParser(GPParser): def write_binary(self, filename): with codecs.open(filename, 'wb+', - self.encoding) as f: + self.output_encoding) as f: + # Write the byte-order mark + f.write(u'\ufeff') + for s in self.sections: self.sections[s].write_section(s, f) diff --git a/source4/selftest/provisions/generalized-gpo-backup/policy/{1E1DC8EA-390C-4800-B327-98B56A0AEA5D}/Machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf.SAMBABACKUP b/source4/selftest/provisions/generalized-gpo-backup/policy/{1E1DC8EA-390C-4800-B327-98B56A0AEA5D}/Machine/Microsoft/Windows NT/SecEdit/GptTmpl.inf.SAMBABACKUP index 18c58a7baa9566be4977086640f4ad8c3e4c38a7..8de94078e703e9adf222dfc0bd4bfff31e797bbd 100644 GIT binary patch delta 10 RcmbOtGEIc(|Gy0)TmTmX1Rwwa delta 8 PcmbOxGDTz~lL!|83>*R^ -- 2.17.1 From 98051741ea5069b0e6fb7274cd1959460c7f95a1 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Mon, 8 Jul 2019 13:42:50 +0200 Subject: [PATCH 006/376] WHATSNEW: add CephFS Snapshot Integration section Bug: https://bugzilla.samba.org/show_bug.cgi?id=14039 Signed-off-by: David Disseldorp Reviewed-by: Aurelien Aptel --- WHATSNEW.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index b07e9eba778..fce43f55cfa 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -59,8 +59,8 @@ worker processes at startup and share the client connections amongst these workers. The number of worker processes can be configured by the 'prefork children' setting in the smb.conf (the default is 4). -Authentication Logging. ------------------------ +Authentication Logging +---------------------- Winbind now logs PAM_AUTH and NTLM_AUTH events, a new attribute "logonId" has been added to the Authentication JSON log messages. This contains a random @@ -254,6 +254,12 @@ CTDB changes swap) utilisation using the existing CTDB_MONITOR_MEMORY_USAGE script configuration variable. +CephFS Snapshot Integration +--------------------------- + +CephFS snapshots can now be exposed as previous file versions using the new +ceph_snapshots VFS module. See the vfs_ceph_snapshots(8) man page for details. + REMOVED FEATURES ================ -- 2.17.1 From 122d7afb50e7d9b67954979b38d4f1b168dfde97 Mon Sep 17 00:00:00 2001 From: Aurelien Aptel Date: Tue, 9 Jul 2019 23:55:30 +0200 Subject: [PATCH 007/376] WHATSNEW: document new debug encryption smb.conf param Bug: https://bugzilla.samba.org/show_bug.cgi?id=14039 Signed-off-by: Aurelien Aptel Reviewed-by: David Disseldorp --- WHATSNEW.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index fce43f55cfa..e91ad51c71b 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -312,6 +312,7 @@ smb.conf changes mangled names Changed default illegal web port Removed fruit:zero_file_id Changed default False + debug encryption New: dump encryption keys False KNOWN ISSUES -- 2.17.1 From b95186a533201b8eeeb49a073e65e60a3a57bf75 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Mon, 8 Jul 2019 16:59:33 +1200 Subject: [PATCH 008/376] ldap_server: Regression in 0559430ab6e5c48d6e853fda0d8b63f2e149015c Extended DN requests seem to have been incorrectly handled. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14029 Signed-off-by: Garming Sam Reviewed-by: Gary Lockyer Autobuild-User(master): Gary Lockyer Autobuild-Date(master): Thu Jul 11 05:25:26 UTC 2019 on sn-devel-184 (cherry picked from commit 9f6b87d3f6cc9930d75c1f8d38ad4f5a37da34ab) --- source4/ldap_server/ldap_backend.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source4/ldap_server/ldap_backend.c b/source4/ldap_server/ldap_backend.c index c6a65122ab0..bf724335a25 100644 --- a/source4/ldap_server/ldap_backend.c +++ b/source4/ldap_server/ldap_backend.c @@ -826,6 +826,7 @@ static NTSTATUS ldapsrv_SearchRequest(struct ldapsrv_call *call) } else { extended_type = 0; } + callback_ctx->extended_type = extended_type; } notification_control = ldb_request_get_control(lreq, LDB_CONTROL_NOTIFICATION_OID); -- 2.17.1 From dd36cafdb96e37eb8ee6b55feb3233dc07558b41 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 31 Jul 2019 01:08:23 +0000 Subject: [PATCH 009/376] tldap: Make memcpy of no controls safe Static analyzers sometimes complain about this case. Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=14029 (cherry picked from commit e5452a37425484a95f90604a3e58e8a731460793) --- source3/lib/tldap_util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source3/lib/tldap_util.c b/source3/lib/tldap_util.c index 152942dab2c..bdf8eb031a5 100644 --- a/source3/lib/tldap_util.c +++ b/source3/lib/tldap_util.c @@ -588,7 +588,9 @@ struct tldap_control *tldap_add_control(TALLOC_CTX *mem_ctx, if (result == NULL) { return NULL; } - memcpy(result, ctrls, sizeof(struct tldap_control) * num_ctrls); + if (num_ctrls > 0) { + memcpy(result, ctrls, sizeof(struct tldap_control) * num_ctrls); + } result[num_ctrls] = *ctrl; return result; } -- 2.17.1 From 23f8a8ee71b6aa2b88174e5d9556508ae48e733e Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 31 Jul 2019 13:39:13 +1200 Subject: [PATCH 010/376] tldap: Paged searches fail when they get to the end The normal case hit the goto label, and should have just returned. Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=14029 (cherry picked from commit bff466943e01540b4d3210392e0fd5b1c882c0b9) --- source3/lib/tldap_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/lib/tldap_util.c b/source3/lib/tldap_util.c index bdf8eb031a5..1b86962a32e 100644 --- a/source3/lib/tldap_util.c +++ b/source3/lib/tldap_util.c @@ -810,7 +810,8 @@ static void tldap_search_paged_done(struct tevent_req *subreq) } tevent_req_set_callback(subreq, tldap_search_paged_done, req); - err: + return; +err: TALLOC_FREE(asn1); tevent_req_ldap_error(req, TLDAP_DECODING_ERROR); -- 2.17.1 From a1d0ce447e782b88386189969afa46f2dc4ed43a Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 31 Jul 2019 15:29:07 +1200 Subject: [PATCH 011/376] tests/tldap: Actually check the paging return code The test never worked correctly because the code was overlooked. It was also the case that the connection was never authenticated, and so an LDAP BIND call has now been added. Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=14029 (cherry picked from commit 85a7b594c56f7729bdfa194fee9299a08f6b4785) --- source3/torture/torture.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 2cb32efea46..20a7459b4db 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -11286,6 +11286,8 @@ static bool run_shortname_test(int dummy) return correct; } +TLDAPRC callback_code; + static void pagedsearch_cb(struct tevent_req *req) { TLDAPRC rc; @@ -11296,6 +11298,7 @@ static void pagedsearch_cb(struct tevent_req *req) if (!TLDAP_RC_IS_SUCCESS(rc)) { d_printf("tldap_search_paged_recv failed: %s\n", tldap_rc2string(rc)); + callback_code = rc; return; } if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) { @@ -11360,6 +11363,18 @@ static bool run_tldap(int dummy) return false; } + rc = tldap_gensec_bind(ld, torture_creds, "ldap", host, NULL, + loadparm_init_s3(talloc_tos(), + loadparm_s3_helpers()), + GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL); + + if (!TLDAP_RC_IS_SUCCESS(rc)) { + d_printf("tldap_gensec_bind failed\n"); + return false; + } + + callback_code = TLDAP_SUCCESS; + req = tldap_search_paged_send(talloc_tos(), ev, ld, basedn, TLDAP_SCOPE_SUB, "(objectclass=*)", NULL, 0, 0, @@ -11374,6 +11389,14 @@ static bool run_tldap(int dummy) TALLOC_FREE(req); + rc = callback_code; + + if (!TLDAP_RC_IS_SUCCESS(rc)) { + d_printf("tldap_search with paging failed: %s\n", + tldap_errstr(talloc_tos(), ld, rc)); + return false; + } + /* test search filters against rootDSE */ filter = "(&(|(name=samba)(nextRid<=10000000)(usnChanged>=10)(samba~=ambas)(!(name=s*m*a)))" "(|(name:=samba)(name:dn:2.5.13.5:=samba)(:dn:2.5.13.5:=samba)(!(name=*samba))))"; -- 2.17.1 From 636f7dedd40d1f357d0b0799496fabeb82e73450 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 31 Jul 2019 01:14:42 +0000 Subject: [PATCH 012/376] tests/ldap: Use TLDAP to check the extended DN return Tests commit 9f6b87d3f6cc9930d75c1f8d38ad4f5a37da34ab To run: make test TESTS="samba3.smbtorture_s3.plain.TLDAP" Reverting the above commit makes this test fail: 'GUID format in control (no hyphens) doesn't match output tldap_search with extended dn (no val) failed: LDAP error 0 (TLDAP_SUCCESS), TEST TLDAP FAILED!' This behaviour couldn't be tested via LDB libraries because they never deal with the underlying DN string. Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett BUG: https://bugzilla.samba.org/show_bug.cgi?id=14029 Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Thu Aug 1 06:20:28 UTC 2019 on sn-devel-184 (adapted from commit 464fef34d1d047d73be347cd446b74e0f5eb2370) --- source3/torture/torture.c | 155 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 20a7459b4db..f26c634b7a7 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -26,6 +26,7 @@ #include "libcli/security/security.h" #include "tldap.h" #include "tldap_util.h" +#include "tldap_gensec_bind.h" #include "../librpc/gen_ndr/svcctl.h" #include "../lib/util/memcache.h" #include "nsswitch/winbind_client.h" @@ -45,6 +46,9 @@ #include "lib/util/base64.h" #include "lib/util/time.h" #include "lib/gencache.h" +#include "lib/util/asn1.h" +#include "lib/param/param.h" +#include "auth/gensec/gensec.h" #include #include @@ -11313,6 +11317,134 @@ static void pagedsearch_cb(struct tevent_req *req) TALLOC_FREE(msg); } +enum tldap_extended_val { + EXTENDED_ZERO = 0, + EXTENDED_ONE = 1, + EXTENDED_NONE = 2, +}; + +/* + * Construct an extended dn control with either no value, 0 or 1 + * + * No value and 0 are equivalent (non-hyphenated GUID) + * 1 has the hyphenated GUID + */ +static struct tldap_control * +tldap_build_extended_control(enum tldap_extended_val val) +{ + struct tldap_control empty_control; + struct asn1_data *data; + + ZERO_STRUCT(empty_control); + + if (val != EXTENDED_NONE) { + data = asn1_init(talloc_tos()); + + if (!data) { + return NULL; + } + + if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) { + return NULL; + } + + if (!asn1_write_Integer(data, (int)val)) { + return NULL; + } + + if (!asn1_pop_tag(data)) { + return NULL; + } + + if (!asn1_blob(data, &empty_control.value)) { + return NULL; + } + } + + empty_control.oid = "1.2.840.113556.1.4.529"; + empty_control.critical = true; + + return tldap_add_control(talloc_tos(), NULL, 0, &empty_control); + +} + +static bool tldap_test_dn_guid_format(struct tldap_context *ld, const char *basedn, + enum tldap_extended_val control_val) +{ + struct tldap_control *control = tldap_build_extended_control(control_val); + char *dn = NULL; + struct tldap_message **msg; + TLDAPRC rc; + + rc = tldap_search(ld, basedn, TLDAP_SCOPE_BASE, + "(objectClass=*)", NULL, 0, 0, + control, 1, NULL, + 0, 0, 0, 0, talloc_tos(), &msg); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + d_printf("tldap_search for domain DN failed: %s\n", + tldap_errstr(talloc_tos(), ld, rc)); + return false; + } + + if (!tldap_entry_dn(msg[0], &dn)) { + d_printf("tldap_search domain DN fetch failed: %s\n", + tldap_errstr(talloc_tos(), ld, rc)); + return false; + } + + d_printf("%s\n", dn); + { + uint32_t time_low; + uint32_t time_mid, time_hi_and_version; + uint32_t clock_seq[2]; + uint32_t node[6]; + char next; + + switch (control_val) { + case EXTENDED_NONE: + case EXTENDED_ZERO: + /* + * When reading GUIDs with hyphens, scanf will treat + * hyphen as a hex character (and counts as part of the + * width). This creates leftover GUID string which we + * check will for with 'next' and closing '>'. + */ + if (12 == sscanf(dn, "%c", + &time_low, &time_mid, + &time_hi_and_version, &clock_seq[0], + &clock_seq[1], &node[0], &node[1], + &node[2], &node[3], &node[4], + &node[5], &next)) { + /* This GUID is good */ + } else { + d_printf("GUID format in control (no hyphens) doesn't match output\n"); + return false; + } + + break; + case EXTENDED_ONE: + if (12 == sscanf(dn, + "%c", + &time_low, &time_mid, + &time_hi_and_version, &clock_seq[0], + &clock_seq[1], &node[0], &node[1], + &node[2], &node[3], &node[4], + &node[5], &next)) { + /* This GUID is good */ + } else { + d_printf("GUID format in control (with hyphens) doesn't match output\n"); + return false; + } + + break; + default: + return false; + } + } + + return true; +} + static bool run_tldap(int dummy) { struct tldap_context *ld; @@ -11410,6 +11542,29 @@ static bool run_tldap(int dummy) return false; } + /* + * Tests to check for regression of: + * + * https://bugzilla.samba.org/show_bug.cgi?id=14029 + * + * TLDAP used here to pick apart the original string DN (with GUID) + */ + if (!tldap_test_dn_guid_format(ld, basedn, EXTENDED_NONE)) { + d_printf("tldap_search with extended dn (no val) failed: %s\n", + tldap_errstr(talloc_tos(), ld, rc)); + return false; + } + if (!tldap_test_dn_guid_format(ld, basedn, EXTENDED_ZERO)) { + d_printf("tldap_search with extended dn (0) failed: %s\n", + tldap_errstr(talloc_tos(), ld, rc)); + return false; + } + if (!tldap_test_dn_guid_format(ld, basedn, EXTENDED_ONE)) { + d_printf("tldap_search with extended dn (1) failed: %s\n", + tldap_errstr(talloc_tos(), ld, rc)); + return false; + } + TALLOC_FREE(ld); return true; } -- 2.17.1 From 816053b7bba894aa217a895925621801f0d17681 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Wed, 24 Jul 2019 11:00:01 +1200 Subject: [PATCH 013/376] join: Use a specific attribute order for the DsAddEntry nTDSDSA object Joining a Windows domain can throw an error if the HasMasterNCs attribute occurs before msDS-HasMasterNCs. This patch changes the attribute order so that msDS-HasMasterNCs is always first. Previously on python2, the dictionary hash order was arbitrary but constant. By luck, msDS-HasMasterNCs was always before HasMasterNCs, so we never noticed any problem. With python3, the dictionary hash order now changes everytime you run the command, so the order is unpredictable. To enforce a order, we can change to use an OrderedDict, which will return the keys in the order they're added. I've asked Microsoft to clarify the protocol requirement here WRT attribute order. However, in the meantime we may as well fix the problem for users. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14046 RN: When trying to join a Windows domain (with functional level 2008R2) as an AD domain controller, the 'samba-tool domain join' command could throw a python exception: 'RuntimeError ("DsAddEntry failed")'. When this problem occurred, you would also see the message "DsAddEntry failed with status WERR_ACCESS_DENIED info (8363, 'WERR_DS_NO_CROSSREF_FOR_NC')" in the command output. This issue has now been resolved. Note that this problem would only occur on Samba v4.10 when using the Python3 packages. Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Wed Jul 24 04:18:21 UTC 2019 on sn-devel-184 (cherry picked from commit 256684c7a86301d26d6cf7298fb70e647bf45cf5) --- python/samba/join.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/python/samba/join.py b/python/samba/join.py index ac4346c62a3..40920f4f8e5 100644 --- a/python/samba/join.py +++ b/python/samba/join.py @@ -48,6 +48,7 @@ import time import re import os import tempfile +from collections import OrderedDict from samba.compat import text_type from samba.compat import get_string from samba.netcmd import CommandError @@ -555,11 +556,14 @@ class DCJoinContext(object): '''return the ntdsdsa object to add''' print("Adding %s" % ctx.ntds_dn) - rec = { - "dn": ctx.ntds_dn, - "objectclass": "nTDSDSA", - "systemFlags": str(samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE), - "dMDLocation": ctx.schema_dn} + + # When joining Windows, the order of certain attributes (mostly only + # msDS-HasMasterNCs and HasMasterNCs) seems to matter + rec = OrderedDict([ + ("dn", ctx.ntds_dn), + ("objectclass", "nTDSDSA"), + ("systemFlags", str(samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE)), + ("dMDLocation", ctx.schema_dn)]) nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn] @@ -575,12 +579,17 @@ class DCJoinContext(object): rec["options"] = "37" else: rec["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn + + # Note that Windows seems to have an undocumented requirement that + # the msDS-HasMasterNCs attribute occurs before HasMasterNCs + if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: + rec["msDS-HasMasterNCs"] = ctx.full_nc_list + rec["HasMasterNCs"] = [] for nc in nc_list: if nc in ctx.full_nc_list: rec["HasMasterNCs"].append(nc) - if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003: - rec["msDS-HasMasterNCs"] = ctx.full_nc_list + rec["options"] = "1" rec["invocationId"] = ndr_pack(ctx.invocation_id) -- 2.17.1 From 8a09ea3c70f95a577ed42123ebe8d3ab26f2c39d Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 24 Jul 2019 15:18:40 +1200 Subject: [PATCH 014/376] netcmd: Allow drs replicate --local to create partitions Currently, neither the offline (--local) or online (normal replica sync) methods allow partition creation post-join. This overrides the Python default to not create the DB, which allows TDB + MDB to work. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14051 Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett (cherry picked from commit d90ccce59754bc833027c06683afac25f7a8d474) --- python/samba/netcmd/drs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/samba/netcmd/drs.py b/python/samba/netcmd/drs.py index 739498cca1b..9d6e8087e87 100644 --- a/python/samba/netcmd/drs.py +++ b/python/samba/netcmd/drs.py @@ -449,8 +449,10 @@ class cmd_drs_replicate(Command): self.server = SOURCE_DC drsuapi_connect(self) + # Override the default flag LDB_FLG_DONT_CREATE_DB self.local_samdb = SamDB(session_info=system_session(), url=None, - credentials=self.creds, lp=self.lp) + credentials=self.creds, lp=self.lp, + flags=0) self.samdb = SamDB(url="ldap://%s" % self.server, session_info=system_session(), -- 2.17.1 From c7a5694f4f81676f89969464645c9ff021680eb2 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 24 Jul 2019 15:13:43 +1200 Subject: [PATCH 015/376] tests: Add samba_upgradedns to the list of possible cmds This will be used to test the replication scenario with no DNS partitions BUG: https://bugzilla.samba.org/show_bug.cgi?id=14051 Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett (cherry picked from commit 7d2875bd70cf727730be8dc705bfd01eacaaaa6f) --- python/samba/tests/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py index c5c212ef829..fef21d261ca 100644 --- a/python/samba/tests/__init__.py +++ b/python/samba/tests/__init__.py @@ -404,6 +404,7 @@ class BlackboxTestCase(TestCaseInTempDir): python_cmds = ["samba-tool", "samba_dnsupdate", + "samba_upgradedns", "script/traffic_replay", "script/traffic_learner"] -- 2.17.1 From 97a742fe7617d153e38aac5ad6c887c79a6e2447 Mon Sep 17 00:00:00 2001 From: Garming Sam Date: Wed, 24 Jul 2019 14:53:33 +1200 Subject: [PATCH 016/376] tests/drs_no_dns: Check dbcheck and ldapcmp pass When joining a DC without DNS partitions, make sure that the alternate flow of creating them afterwards results in a database with everything that is necessary. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14051 RN: Allow a DC join without DNS partitions, to add them later Signed-off-by: Garming Sam Reviewed-by: Andrew Bartlett (cherry picked from commit 35c54007e6183829d9d85a24b3bd95f469739ad3) --- source4/selftest/tests.py | 7 + .../drs/python/samba_tool_drs_no_dns.py | 183 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 source4/torture/drs/python/samba_tool_drs_no_dns.py diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 1a7e8c757f0..bf3dd98cbef 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -949,6 +949,13 @@ for env in ['backupfromdc', 'offlinebackupdc', 'restoredc', 'renamedc', plantestsuite("samba4.blackbox.join_ldapcmp", env, ["PYTHON=%s" % python, os.path.join(bbdir, "join_ldapcmp.sh")]) +env = 'backupfromdc' +planoldpythontestsuite("%s:local" % env, "samba_tool_drs_no_dns", + extra_path=[os.path.join(samba4srcdir, 'torture/drs/python')], + name="samba4.drs.samba_tool_drs_no_dns.python(%s)" % env, + environ={'DC1': '$DC_SERVER', 'DC2': '$DC_SERVER'}, + extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD']) + plantestsuite_loadlist("samba4.ldap.rodc.python(rodc)", "rodc", [python, os.path.join(DSDB_PYTEST_DIR, "rodc.py"), diff --git a/source4/torture/drs/python/samba_tool_drs_no_dns.py b/source4/torture/drs/python/samba_tool_drs_no_dns.py new file mode 100644 index 00000000000..b9cab49e82b --- /dev/null +++ b/source4/torture/drs/python/samba_tool_drs_no_dns.py @@ -0,0 +1,183 @@ +# Blackbox tests for "samba-tool drs" command +# Copyright (C) Kamen Mazdrashki 2011 +# Copyright (C) Andrew Bartlett 2017 +# Copyright (C) Catalyst.Net Ltd 2019 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +""" +Blackbox tests for samba-tool drs with no DNS partitions + +Adapted from samba_tool_drs.py +""" + +import samba.tests +import shutil +import os +import ldb +import drs_base + +from samba.tests import BlackboxProcessError +from samba.compat import get_string + + +class SambaToolDrsNoDnsTests(drs_base.DrsBaseTestCase): + """Blackbox test case for samba-tool drs.""" + + def setUp(self): + super(SambaToolDrsNoDnsTests, self).setUp() + + self.dc1 = samba.tests.env_get_var_value("DC1") + + creds = self.get_credentials() + self.cmdline_creds = "-U%s/%s%%%s" % (creds.get_domain(), + creds.get_username(), creds.get_password()) + + def tearDown(self): + self._enable_inbound_repl(self.dnsname_dc1) + + try: + shutil.rmtree(os.path.join(self.tempdir, "private")) + shutil.rmtree(os.path.join(self.tempdir, "etc")) + shutil.rmtree(os.path.join(self.tempdir, "msg.lock")) + os.remove(os.path.join(self.tempdir, "names.tdb")) + shutil.rmtree(os.path.join(self.tempdir, "state")) + shutil.rmtree(os.path.join(self.tempdir, "bind-dns")) + except Exception: + pass + + super(SambaToolDrsNoDnsTests, self).tearDown() + + def _get_rootDSE(self, dc, ldap_only=True): + samdb = samba.tests.connect_samdb(dc, lp=self.get_loadparm(), + credentials=self.get_credentials(), + ldap_only=ldap_only) + return samdb.search(base="", scope=samba.tests.ldb.SCOPE_BASE)[0], samdb + + def test_samba_tool_replicate_local_no_dns_tdb(self): + self.backend = 'tdb' + self._test_samba_tool_replicate_local_no_dns() + + def test_samba_tool_replicate_local_no_dns_mdb(self): + self.backend = 'mdb' + self._test_samba_tool_replicate_local_no_dns() + + def _test_samba_tool_replicate_local_no_dns(self): + """Check we can provision a database without DNS partitions + (and then add them afterwards).""" + + server_rootdse, _ = self._get_rootDSE(self.dc1) + nc_name = server_rootdse["defaultNamingContext"] + server_ldap_service_name = str(server_rootdse["ldapServiceName"][0]) + server_realm = server_ldap_service_name.split(":")[0] + creds = self.get_credentials() + + # We have to give it a different netbiosname every time + # it runs, otherwise the collision causes strange issues + # to happen. This should be different on different environments. + netbiosname = "dns" + self.backend + self.dc1 + if len(netbiosname) > 15: + netbiosname = netbiosname[:15] + + out = self.check_output("samba-tool domain join %s dc --server=%s %s --targetdir=%s --option=netbiosname=%s %s --backend-store=%s" + % (server_realm, self.dc1, self.cmdline_creds, + self.tempdir, netbiosname, + "--dns-backend=NONE", + self.backend)) + + new_dc_config_file = os.path.join(self.tempdir, "etc", "smb.conf") + new_dc_sam = os.path.join(self.tempdir, "private", "sam.ldb") + + forestdns_dn = ldb.binary_encode('DC=ForestDNSZones,' + str(nc_name)) + domaindns_dn = ldb.binary_encode('DC=DomainDNSZones,' + str(nc_name)) + + self.check_output("samba-tool drs replicate --local %s %s %s %s -s %s --full-sync" + % ("invalid", self.dc1, forestdns_dn, + self.cmdline_creds, new_dc_config_file)) + + self.check_output("samba-tool drs replicate --local %s %s %s %s -s %s --full-sync" + % ("invalid", self.dc1, domaindns_dn, + self.cmdline_creds, new_dc_config_file)) + + server_rootdse, samdb = self._get_rootDSE("ldb://" + new_dc_sam, ldap_only=False) + server_ds_name = ldb.binary_encode(server_rootdse["dsServiceName"][0].decode('utf-8')) + + # Show that Has-Master-NCs is fixed by samba_upgradedns + res = samdb.search(base=server_ds_name, + expression="(msds-hasmasterncs=%s)" % forestdns_dn) + self.assertEquals(len(res), 0) + res = samdb.search(base=server_ds_name, + expression="(msds-hasmasterncs=%s)" % domaindns_dn) + self.assertEquals(len(res), 0) + + self.check_output("samba_upgradedns -s %s" % (new_dc_config_file)) + + res = samdb.search(base=server_ds_name, + expression="(msds-hasmasterncs=%s)" % forestdns_dn) + self.assertEquals(len(res), 1) + res = samdb.search(base=server_ds_name, + expression="(msds-hasmasterncs=%s)" % domaindns_dn) + self.assertEquals(len(res), 1) + + # Show that replica locations is fixed by dbcheck + res = samdb.search(controls=["search_options:1:2"], + expression="(&(msds-nc-replica-locations=%s)(ncname=%s))" + % (server_ds_name, forestdns_dn)) + self.assertEquals(len(res), 0) + res = samdb.search(controls=["search_options:1:2"], + expression="(&(msds-nc-replica-locations=%s)(ncname=%s))" + % (server_ds_name, domaindns_dn)) + self.assertEquals(len(res), 0) + + try: + # This fixes any forward-link-backward-link issues with the tools + self.check_output("samba-tool dbcheck -s %s --cross-ncs --fix --yes" % (new_dc_config_file)) + except BlackboxProcessError as e: + self.assertTrue("Checked " in get_string(e.stdout)) + + self.check_output("samba-tool dbcheck -s %s --cross-ncs" % (new_dc_config_file)) + + # Compare the two directories + self.check_output("samba-tool ldapcmp ldap://%s ldb://%s %s --filter=%s" % + (self.dc1, new_dc_sam, self.cmdline_creds, + "msDs-masteredBy,msDS-NC-Replica-Locations,msDS-hasMasterNCs")) + + # Check all ForestDNS connections and backlinks + res = samdb.search(base=server_ds_name, + expression="(msds-hasmasterncs=%s)" % forestdns_dn) + self.assertEquals(len(res), 1) + res = samdb.search(base=forestdns_dn, + expression="(msds-masteredby=%s)" % server_ds_name) + self.assertEquals(len(res), 1) + res = samdb.search(controls=["search_options:1:2"], + expression="(&(msds-nc-replica-locations=%s)(ncname=%s))" + % (server_ds_name, forestdns_dn)) + self.assertEquals(len(res), 1) + + # Check all DomainDNS connections and backlinks + res = samdb.search(base=server_ds_name, + expression="(msds-hasmasterncs=%s)" % domaindns_dn) + self.assertEquals(len(res), 1) + res = samdb.search(base=domaindns_dn, + expression="(msds-masteredby=%s)" % server_ds_name) + self.assertEquals(len(res), 1) + res = samdb.search(controls=["search_options:1:2"], + expression="(&(msds-nc-replica-locations=%s)(ncname=%s))" + % (server_ds_name, domaindns_dn)) + self.assertEquals(len(res), 1) + + # Demote the DC we created in the test + self.check_output("samba-tool domain demote --remove-other-dead-server=%s -H ldap://%s %s -s %s" + % (netbiosname, self.dc1, self.cmdline_creds, new_dc_config_file)) -- 2.17.1 From 02352ebbef6dd5669cb28369a3c7e7579c796384 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Mon, 29 Jul 2019 10:14:06 +1200 Subject: [PATCH 017/376] WHATSNEW: Make it clearer how the AD database changes will affect users The release notes currently just have a brief mention of a new LDB pack format. They don't really cover how this change will actually affect AD users when upgrading (or more specifically downgrading) with v4.11. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14057 Signed-off-by: Tim Beale --- WHATSNEW.txt | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index e91ad51c71b..c94b3541d7d 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -12,6 +12,32 @@ Samba 4.11 will be the next version of the Samba suite. UPGRADING ========= +AD Database compatibility +------------------------- + +Samba v4.11 has changed how the AD database is stored on disk. AD users should +not really be affected by this change when upgrading to v4.11. However, AD +users should be extremely careful if they need to downgrade from Samba v4.11 to +an older release. + +Samba v4.11 maintains database compatibility with older Samba releases. The +database will automatically get rewritten in the new v4.11 format when you +first start the upgraded samba executable. + +However, when downgrading from v4.11 you will need to manually downgrade the AD +database yourself. Note that you will need to do this step before you install +the downgraded Samba packages. For more details, see: +https://wiki.samba.org/index.php/Downgrading_an_Active_Directory_DC + +When either upgrading or downgrading, users should also avoid making any +database modifications between installing the new Samba packages and starting +the samba executable. + +Note that when moving between major Samba releases in general, we recommend +that the AD DC is rejoined to the domain. Using this approach avoids the need +to explicitly downgrade the database manually. For more details, see: +https://wiki.samba.org/index.php/Upgrading_a_Samba_AD_DC + SMB1 is disabled by default --------------------------- -- 2.17.1 From 6b4c51d0c94a34ccd310f4c0e470f043407659d6 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Mon, 29 Jul 2019 10:35:23 +1200 Subject: [PATCH 018/376] WHATSNEW: Add link to 2012 Windows compatibility wiki page There's now a lot more info on the wiki on Windows 2012 compatibility, and how the schema is just a small part of overall compatibility. Link to this wiki page from the WHATSNEW, so users can read more about this. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14057 Signed-off-by: Tim Beale --- WHATSNEW.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index c94b3541d7d..3276d884f3a 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -142,6 +142,10 @@ Samba's replication code has also been improved to handle replication with the 2012 schema (the core of this replication fix has also been backported to 4.9.11 and will be in a 4.10.x release). +For more about how the AD schema relates to overall Windows compatibility, +please read: +https://wiki.samba.org/index.php/Windows_2012_Server_compatibility + GnuTLS 3.2 required ------------------- -- 2.17.1 From 62e65124e9d720d5dd27d822e7a25df24ea9f81b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 31 Jul 2019 14:17:02 +0200 Subject: [PATCH 019/376] smbd: Fix use-after-free from exit_server_common() We need to keep the smbXsrv_connection structures around until all pending requests have had their chance to clean up behind them. If you look at srv_send_smb(), it's exactly prepared already to just drop anything on the floor when the transport has been declared dead: if (!NT_STATUS_IS_OK(xconn->transport.status)) { /* * we're not supposed to do any io */ return true; } Bug: https://bugzilla.samba.org/show_bug.cgi?id=14064 Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Thu Aug 1 15:39:13 UTC 2019 on sn-devel-184 (cherry picked from commit c226dc6e8a18343031829c35552e557903593daf) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Wed Aug 7 12:53:51 UTC 2019 on sn-devel-184 --- source3/smbd/server_exit.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/source3/smbd/server_exit.c b/source3/smbd/server_exit.c index 2378c0c15ca..b21501a7a23 100644 --- a/source3/smbd/server_exit.c +++ b/source3/smbd/server_exit.c @@ -91,7 +91,6 @@ static void exit_server_common(enum server_exit_reason how, { struct smbXsrv_client *client = global_smbXsrv_client; struct smbXsrv_connection *xconn = NULL; - struct smbXsrv_connection *xconn_next = NULL; struct smbd_server_connection *sconn = NULL; struct messaging_context *msg_ctx = global_messaging_context(); @@ -110,10 +109,7 @@ static void exit_server_common(enum server_exit_reason how, /* * Here we typically have just one connection */ - for (; xconn != NULL; xconn = xconn_next) { - xconn_next = xconn->next; - DLIST_REMOVE(client->connections, xconn); - + for (; xconn != NULL; xconn = xconn->next) { /* * This is typically the disconnect for the only * (or with multi-channel last) connection of the client @@ -128,8 +124,6 @@ static void exit_server_common(enum server_exit_reason how, break; } } - - TALLOC_FREE(xconn); DO_PROFILE_INC(disconnect); } @@ -172,6 +166,20 @@ static void exit_server_common(enum server_exit_reason how, change_to_root_user(); + if (client != NULL) { + struct smbXsrv_connection *xconn_next = NULL; + + for (xconn = client->connections; + xconn != NULL; + xconn = xconn_next) { + xconn_next = xconn->next; + DLIST_REMOVE(client->connections, xconn); + TALLOC_FREE(xconn); + } + } + + change_to_root_user(); + /* 3 second timeout. */ print_notify_send_messages(msg_ctx, 3); -- 2.17.1 From 428ecb5f4e2bb399e90f50dcd56054062bbaf85a Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 13 Aug 2019 11:33:01 +0200 Subject: [PATCH 020/376] WHATSNEW: Fix some minor formatting issues. Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 3276d884f3a..6a0cc9d72fd 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -15,16 +15,16 @@ UPGRADING AD Database compatibility ------------------------- -Samba v4.11 has changed how the AD database is stored on disk. AD users should -not really be affected by this change when upgrading to v4.11. However, AD -users should be extremely careful if they need to downgrade from Samba v4.11 to +Samba 4.11 has changed how the AD database is stored on disk. AD users should +not really be affected by this change when upgrading to 4.11. However, AD +users should be extremely careful if they need to downgrade from Samba 4.11 to an older release. -Samba v4.11 maintains database compatibility with older Samba releases. The -database will automatically get rewritten in the new v4.11 format when you +Samba 4.11 maintains database compatibility with older Samba releases. The +database will automatically get rewritten in the new 4.11 format when you first start the upgraded samba executable. -However, when downgrading from v4.11 you will need to manually downgrade the AD +However, when downgrading from 4.11 you will need to manually downgrade the AD database yourself. Note that you will need to do this step before you install the downgraded Samba packages. For more details, see: https://wiki.samba.org/index.php/Downgrading_an_Active_Directory_DC @@ -56,7 +56,7 @@ and LANMAN1 for client and server, as well as CORE and COREPLUS on the client. Note that most commandline tools e.g. smbclient, smbcacls and others -also support the --option argument to overwrite smb.conf options, +also support the '--option' argument to overwrite smb.conf options, e.g. --option='client min protocol=NT1' might be useful. As Microsoft no longer installs SMB1 support in recent releases @@ -74,7 +74,7 @@ NEW FEATURES/CHANGES Default samba process model --------------------------- -The default for the --model argument passed to the samba executable has changed +The default for the '--model' argument passed to the samba executable has changed from 'standard' to 'prefork'. This means a difference in the number of samba child processes that are created to handle client connections. The previous default would create a separate process for every LDAP or NETLOGON client @@ -102,26 +102,27 @@ where: is the name of the command makinmg the winbind request i.e. wbinfo is the process id of the requesting process. -The version of the JSON Authentication messages has been changed to 1.2 from 1.1 +The version of the JSON Authentication messages has been changed from 1.1 to +1.2. LDAP referrals -------------- The scheme of returned LDAP referrals now reflects the scheme of the original request, i.e. referrals received via ldap are prefixed with "ldap://" -and those over ldaps are prefixed with "ldaps://" +and those over ldaps are prefixed with "ldaps://". -Previously all referrals were prefixed with "ldap://" +Previously all referrals were prefixed with "ldap://". Bind9 logging ------------- -It is now possible to log the duration of DNS operations performed by Bind9 -This should aid future diagnosis of performance issues, and could be used to +It is now possible to log the duration of DNS operations performed by Bind9. +This should aid future diagnosis of performance issues and could be used to monitor DNS performance. The logging is enabled by setting log level to -"dns:10" in smb.conf +"dns:10" in smb.conf. -The logs are currently Human readable text only, i.e. no JSON formatted output. +The logs are currently human readable text only, i.e. no JSON formatted output. Log lines are of the form: @@ -210,7 +211,7 @@ multiple times into memory. Setting lmdb map size --------------------- -It is now possible to set the lmdb map size (The maximum permitted +It is now possible to set the lmdb map size (the maximum permitted size for the database). "samba-tool" now accepts the "--backend-store-size" i.e. --backend-store-size=4Gb. If not specified it defaults to 8Gb. @@ -302,14 +303,12 @@ Samba still supported a Python WSGI web server (which could still be turned on from the 'server services' smb.conf parameter). This service was unused and has now been removed from Samba. - samba-tool join subdomain ------------------------- The subdomain role has been removed from the join command. This option did not work and has no tests. - Python2 support --------------- -- 2.17.1 From 8dfa63d9f7236a534fb454e50e6dff41d07ae89c Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Thu, 1 Aug 2019 21:08:52 +0300 Subject: [PATCH 021/376] torture/rpc/lsa: allow testing different lookup levels Convert torture/rpc/lsa LookupNames/LookupSids code to allow testing different LSA_LOOKUP_NAMES_* levels. Keep existing level 1 (LSA_LOOKUP_NAMES_ALL) for the current set of tests. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14091 Signed-off-by: Alexander Bokovoy Reviewed-by: Andreas Schneider (cherry picked from commit 317bc6a7342edfa2c503f5932142bf5883485cc9) --- source4/torture/rpc/lsa.c | 118 ++++++++++++++++++--------------- source4/torture/rpc/schannel.c | 2 +- 2 files changed, 67 insertions(+), 53 deletions(-) diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c index 5b16ed9a014..fdbfcbffc16 100644 --- a/source4/torture/rpc/lsa.c +++ b/source4/torture/rpc/lsa.c @@ -281,6 +281,7 @@ static bool test_OpenPolicy2_fail(struct dcerpc_binding_handle *b, static bool test_LookupNames(struct dcerpc_binding_handle *b, struct torture_context *tctx, struct policy_handle *handle, + enum lsa_LookupNamesLevel level, struct lsa_TransNameArray *tnames) { struct lsa_LookupNames r; @@ -313,7 +314,7 @@ static bool test_LookupNames(struct dcerpc_binding_handle *b, r.in.handle = handle; r.in.names = names; r.in.sids = &sids; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.out.count = &count; r.out.sids = &sids; @@ -369,7 +370,8 @@ static bool test_LookupNames(struct dcerpc_binding_handle *b, static bool test_LookupNames_bogus(struct dcerpc_binding_handle *b, struct torture_context *tctx, - struct policy_handle *handle) + struct policy_handle *handle, + enum lsa_LookupNamesLevel level) { struct lsa_LookupNames r; struct lsa_TransSidArray sids; @@ -388,7 +390,7 @@ static bool test_LookupNames_bogus(struct dcerpc_binding_handle *b, r.in.num_names = 1; r.in.names = names; r.in.sids = &sids; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.out.count = &count; r.out.sids = &sids; @@ -409,7 +411,8 @@ static bool test_LookupNames_bogus(struct dcerpc_binding_handle *b, static bool test_LookupNames_NULL(struct dcerpc_binding_handle *b, struct torture_context *tctx, - struct policy_handle *handle) + struct policy_handle *handle, + enum lsa_LookupNamesLevel level) { struct lsa_LookupNames r; struct lsa_TransSidArray sids; @@ -428,7 +431,7 @@ static bool test_LookupNames_NULL(struct dcerpc_binding_handle *b, r.in.num_names = 1; r.in.names = names; r.in.sids = &sids; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.out.count = &count; r.out.sids = &sids; @@ -453,7 +456,8 @@ static bool test_LookupNames_NULL(struct dcerpc_binding_handle *b, static bool test_LookupNames_wellknown(struct dcerpc_binding_handle *b, struct torture_context *tctx, - struct policy_handle *handle) + struct policy_handle *handle, + enum lsa_LookupNamesLevel level) { struct lsa_TranslatedName name; struct lsa_TransNameArray tnames; @@ -465,45 +469,46 @@ static bool test_LookupNames_wellknown(struct dcerpc_binding_handle *b, tnames.count = 1; name.name.string = "NT AUTHORITY\\SYSTEM"; name.sid_type = SID_NAME_WKN_GRP; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); name.name.string = "NT AUTHORITY\\ANONYMOUS LOGON"; name.sid_type = SID_NAME_WKN_GRP; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); name.name.string = "NT AUTHORITY\\Authenticated Users"; name.sid_type = SID_NAME_WKN_GRP; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); #if 0 name.name.string = "NT AUTHORITY"; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); name.name.string = "NT AUTHORITY\\"; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); #endif name.name.string = "BUILTIN\\"; name.sid_type = SID_NAME_DOMAIN; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); name.name.string = "BUILTIN\\Administrators"; name.sid_type = SID_NAME_ALIAS; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); name.name.string = "SYSTEM"; name.sid_type = SID_NAME_WKN_GRP; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); name.name.string = "Everyone"; name.sid_type = SID_NAME_WKN_GRP; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, level, &tnames); return ret; } static bool test_LookupNames2(struct dcerpc_binding_handle *b, struct torture_context *tctx, struct policy_handle *handle, + enum lsa_LookupNamesLevel level, struct lsa_TransNameArray2 *tnames, bool check_result) { @@ -536,7 +541,7 @@ static bool test_LookupNames2(struct dcerpc_binding_handle *b, r.in.handle = handle; r.in.names = names; r.in.sids = &sids; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.in.lookup_options = 0; r.in.client_revision = 0; @@ -565,6 +570,7 @@ static bool test_LookupNames2(struct dcerpc_binding_handle *b, static bool test_LookupNames3(struct dcerpc_binding_handle *b, struct torture_context *tctx, struct policy_handle *handle, + enum lsa_LookupNamesLevel level, struct lsa_TransNameArray2 *tnames, bool check_result) { @@ -596,7 +602,7 @@ static bool test_LookupNames3(struct dcerpc_binding_handle *b, r.in.handle = handle; r.in.names = names; r.in.sids = &sids; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.in.lookup_options = 0; r.in.client_revision = 0; @@ -624,6 +630,7 @@ static bool test_LookupNames3(struct dcerpc_binding_handle *b, static bool test_LookupNames4(struct dcerpc_binding_handle *b, struct torture_context *tctx, + enum lsa_LookupNamesLevel level, struct lsa_TransNameArray2 *tnames, bool check_result) { @@ -655,7 +662,7 @@ static bool test_LookupNames4(struct dcerpc_binding_handle *b, r.in.num_names = tnames->count; r.in.names = names; r.in.sids = &sids; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.in.lookup_options = 0; r.in.client_revision = 0; @@ -693,7 +700,8 @@ static bool test_LookupNames4(struct dcerpc_binding_handle *b, } static bool test_LookupNames4_fail(struct dcerpc_binding_handle *b, - struct torture_context *tctx) + struct torture_context *tctx, + enum lsa_LookupNamesLevel level) { struct lsa_LookupNames4 r; struct lsa_TransSidArray3 sids; @@ -712,7 +720,7 @@ static bool test_LookupNames4_fail(struct dcerpc_binding_handle *b, r.in.num_names = count; r.in.names = names; r.in.sids = &sids; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.in.lookup_options = 0; r.in.client_revision = 0; @@ -760,6 +768,7 @@ static bool test_LookupNames4_fail(struct dcerpc_binding_handle *b, static bool test_LookupSids(struct dcerpc_binding_handle *b, struct torture_context *tctx, struct policy_handle *handle, + enum lsa_LookupNamesLevel level, struct lsa_SidArray *sids) { struct lsa_LookupSids r; @@ -775,7 +784,7 @@ static bool test_LookupSids(struct dcerpc_binding_handle *b, r.in.handle = handle; r.in.sids = sids; r.in.names = &names; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.out.count = &count; r.out.names = &names; @@ -790,7 +799,7 @@ static bool test_LookupSids(struct dcerpc_binding_handle *b, torture_comment(tctx, "\n"); - if (!test_LookupNames(b, tctx, handle, &names)) { + if (!test_LookupNames(b, tctx, handle, level, &names)) { return false; } @@ -801,6 +810,7 @@ static bool test_LookupSids(struct dcerpc_binding_handle *b, static bool test_LookupSids2(struct dcerpc_binding_handle *b, struct torture_context *tctx, struct policy_handle *handle, + enum lsa_LookupNamesLevel level, struct lsa_SidArray *sids) { struct lsa_LookupSids2 r; @@ -816,7 +826,7 @@ static bool test_LookupSids2(struct dcerpc_binding_handle *b, r.in.handle = handle; r.in.sids = sids; r.in.names = &names; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.in.lookup_options = 0; r.in.client_revision = 0; @@ -835,11 +845,11 @@ static bool test_LookupSids2(struct dcerpc_binding_handle *b, torture_comment(tctx, "\n"); - if (!test_LookupNames2(b, tctx, handle, &names, false)) { + if (!test_LookupNames2(b, tctx, handle, level, &names, false)) { return false; } - if (!test_LookupNames3(b, tctx, handle, &names, false)) { + if (!test_LookupNames3(b, tctx, handle, level, &names, false)) { return false; } @@ -848,6 +858,7 @@ static bool test_LookupSids2(struct dcerpc_binding_handle *b, static bool test_LookupSids3(struct dcerpc_binding_handle *b, struct torture_context *tctx, + enum lsa_LookupNamesLevel level, struct lsa_SidArray *sids) { struct lsa_LookupSids3 r; @@ -862,7 +873,7 @@ static bool test_LookupSids3(struct dcerpc_binding_handle *b, r.in.sids = sids; r.in.names = &names; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.in.lookup_options = 0; r.in.client_revision = 0; @@ -891,7 +902,7 @@ static bool test_LookupSids3(struct dcerpc_binding_handle *b, torture_comment(tctx, "\n"); - if (!test_LookupNames4(b, tctx, &names, true)) { + if (!test_LookupNames4(b, tctx, level, &names, true)) { return false; } @@ -900,6 +911,7 @@ static bool test_LookupSids3(struct dcerpc_binding_handle *b, static bool test_LookupSids3_fail(struct dcerpc_binding_handle *b, struct torture_context *tctx, + enum lsa_LookupNamesLevel level, struct lsa_SidArray *sids) { struct lsa_LookupSids3 r; @@ -915,7 +927,7 @@ static bool test_LookupSids3_fail(struct dcerpc_binding_handle *b, r.in.sids = sids; r.in.names = &names; - r.in.level = 1; + r.in.level = level; r.in.count = &count; r.in.lookup_options = 0; r.in.client_revision = 0; @@ -959,7 +971,8 @@ static bool test_LookupSids3_fail(struct dcerpc_binding_handle *b, bool test_many_LookupSids(struct dcerpc_pipe *p, struct torture_context *tctx, - struct policy_handle *handle) + struct policy_handle *handle, + enum lsa_LookupNamesLevel level) { uint32_t count; struct lsa_SidArray sids; @@ -990,7 +1003,7 @@ bool test_many_LookupSids(struct dcerpc_pipe *p, r.in.handle = handle; r.in.sids = &sids; r.in.names = &names; - r.in.level = 1; + r.in.level = level; r.in.count = &names.count; r.out.count = &count; r.out.names = &names; @@ -1006,16 +1019,16 @@ bool test_many_LookupSids(struct dcerpc_pipe *p, torture_comment(tctx, "\n"); - if (!test_LookupNames(b, tctx, handle, &names)) { + if (!test_LookupNames(b, tctx, handle, level, &names)) { return false; } } if (transport == NCACN_NP) { - if (!test_LookupSids3_fail(b, tctx, &sids)) { + if (!test_LookupSids3_fail(b, tctx, level, &sids)) { return false; } - if (!test_LookupNames4_fail(b, tctx)) { + if (!test_LookupNames4_fail(b, tctx, level)) { return false; } } else if (transport == NCACN_IP_TCP) { @@ -1031,10 +1044,10 @@ bool test_many_LookupSids(struct dcerpc_pipe *p, if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL && auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) { - if (!test_LookupSids3(b, tctx, &sids)) { + if (!test_LookupSids3(b, tctx, level, &sids)) { return false; } - if (!test_LookupNames4(b, tctx, &names, true)) { + if (!test_LookupNames4(b, tctx, level, &names, true)) { return false; } } else { @@ -1042,10 +1055,10 @@ bool test_many_LookupSids(struct dcerpc_pipe *p, * If we don't have a secure channel these tests must * fail with ACCESS_DENIED. */ - if (!test_LookupSids3_fail(b, tctx, &sids)) { + if (!test_LookupSids3_fail(b, tctx, level, &sids)) { return false; } - if (!test_LookupNames4_fail(b, tctx)) { + if (!test_LookupNames4_fail(b, tctx, level)) { return false; } } @@ -1077,7 +1090,8 @@ static void lookupsids_cb(struct tevent_req *subreq) static bool test_LookupSids_async(struct dcerpc_binding_handle *b, struct torture_context *tctx, - struct policy_handle *handle) + struct policy_handle *handle, + enum lsa_LookupNamesLevel level) { struct lsa_SidArray sids; struct lsa_SidPtr sidptr; @@ -1112,7 +1126,7 @@ static bool test_LookupSids_async(struct dcerpc_binding_handle *b, r[i].in.handle = handle; r[i].in.sids = &sids; r[i].in.names = &names[i]; - r[i].in.level = 1; + r[i].in.level = level; r[i].in.count = &names[i].count; r[i].out.count = &count[i]; r[i].out.names = &names[i]; @@ -1923,11 +1937,11 @@ static bool test_EnumAccounts(struct dcerpc_binding_handle *b, torture_assert_ntstatus_ok(tctx, r.out.result, "EnumAccounts failed"); - if (!test_LookupSids(b, tctx, handle, &sids1)) { + if (!test_LookupSids(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &sids1)) { return false; } - if (!test_LookupSids2(b, tctx, handle, &sids1)) { + if (!test_LookupSids2(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &sids1)) { return false; } @@ -4836,7 +4850,7 @@ static bool test_QueryInfoPolicyCalls( bool version2, tnames.names[12].sid_type = SID_NAME_USER; tnames.names[13].name.string = talloc_asprintf(tctx, TEST_MACHINENAME "$@%s", info->dns.dns_domain.string); tnames.names[13].sid_type = SID_NAME_USER; - ret &= test_LookupNames(b, tctx, handle, &tnames); + ret &= test_LookupNames(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames); } } @@ -5002,7 +5016,7 @@ bool torture_rpc_lsa(struct torture_context *tctx) ret = false; } - if (!test_many_LookupSids(p, tctx, handle)) { + if (!test_many_LookupSids(p, tctx, handle, LSA_LOOKUP_NAMES_ALL)) { ret = false; } @@ -5023,7 +5037,7 @@ bool torture_rpc_lsa(struct torture_context *tctx) ret = false; } - if (!test_LookupSids_async(b, tctx, handle)) { + if (!test_LookupSids_async(b, tctx, handle, LSA_LOOKUP_NAMES_ALL)) { ret = false; } @@ -5047,7 +5061,7 @@ bool torture_rpc_lsa(struct torture_context *tctx) ret = false; } - if (!test_many_LookupSids(p, tctx, handle)) { + if (!test_many_LookupSids(p, tctx, handle, LSA_LOOKUP_NAMES_ALL)) { ret = false; } @@ -5058,7 +5072,7 @@ bool torture_rpc_lsa(struct torture_context *tctx) torture_leave_domain(tctx, join); } else { - if (!test_many_LookupSids(p, tctx, handle)) { + if (!test_many_LookupSids(p, tctx, handle, LSA_LOOKUP_NAMES_ALL)) { ret = false; } } @@ -5133,7 +5147,7 @@ static bool testcase_LookupNames(struct torture_context *tctx, tnames.names[0].name.string = "BUILTIN"; tnames.names[0].sid_type = SID_NAME_DOMAIN; - if (!test_LookupNames(b, tctx, handle, &tnames)) { + if (!test_LookupNames(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames)) { ret = false; } @@ -5143,23 +5157,23 @@ static bool testcase_LookupNames(struct torture_context *tctx, tnames2.names[0].name.string = "BUILTIN"; tnames2.names[0].sid_type = SID_NAME_DOMAIN; - if (!test_LookupNames2(b, tctx, handle, &tnames2, true)) { + if (!test_LookupNames2(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames2, true)) { ret = false; } - if (!test_LookupNames3(b, tctx, handle, &tnames2, true)) { + if (!test_LookupNames3(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames2, true)) { ret = false; } - if (!test_LookupNames_wellknown(b, tctx, handle)) { + if (!test_LookupNames_wellknown(b, tctx, handle, LSA_LOOKUP_NAMES_ALL)) { ret = false; } - if (!test_LookupNames_NULL(b, tctx, handle)) { + if (!test_LookupNames_NULL(b, tctx, handle, LSA_LOOKUP_NAMES_ALL)) { ret = false; } - if (!test_LookupNames_bogus(b, tctx, handle)) { + if (!test_LookupNames_bogus(b, tctx, handle, LSA_LOOKUP_NAMES_ALL)) { ret = false; } diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c index 5b40af216a5..fff0b1aacbd 100644 --- a/source4/torture/rpc/schannel.c +++ b/source4/torture/rpc/schannel.c @@ -470,7 +470,7 @@ static bool test_schannel(struct torture_context *tctx, "failed to connect lsarpc with schannel"); torture_assert(tctx, - test_many_LookupSids(p_lsa, tctx, NULL), + test_many_LookupSids(p_lsa, tctx, NULL, LSA_LOOKUP_NAMES_ALL), "LsaLookupSids3 failed!\n"); status = dcerpc_binding_set_transport(b, transport); -- 2.17.1 From 60d222327343599d13643ee54e041cd65373a7eb Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Thu, 1 Aug 2019 15:48:58 +0300 Subject: [PATCH 022/376] lookup_name: allow own domain lookup when flags == 0 In 2007, we've added support for multiple lookup levels for LSA LookupNames family of calls. However, forest-wide lookups, as described in MS-LSAT 2.2.16, never worked because flags passed to lookup_name() were always set to zero, expecting at least default lookup on a DC to apply. lookup_name() was instead treating zero flags as 'skip all checks'. Allow at least own domain lookup in case domain name is the same. This should allow FreeIPA DC to respond to LSA LookupNames3 calls from a trusted AD DC side. For the reference, below is a request Windows Server 2016 domain controller sends to FreeIPA domain controller when attempting to look up a user from a trusted forest root domain that attemps to login to the domain controller. Notice the level in the lsa_LookupNames3 call and resulting flags in lookup_name(). [2019/08/03 07:14:24.156065, 1, pid=23639, effective(967001000, 967001000), real(967001000, 0), class=rpc_parse] ../../librpc/ndr/ndr.c:471(ndr_print_function_debug) lsa_LookupNames3: struct lsa_LookupNames3 in: struct lsa_LookupNames3 handle : * handle: struct policy_handle handle_type : 0x00000000 (0) uuid : 0000004c-0000-0000-455d-3018575c0000 num_names : 0x00000001 (1) names: ARRAY(1) names: struct lsa_String length : 0x000a (10) size : 0x000c (12) string : * string : 'XS\ab' sids : * sids: struct lsa_TransSidArray3 count : 0x00000000 (0) sids : NULL level : LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 (6) count : * count : 0x00000000 (0) lookup_options : LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES (0) client_revision : LSA_CLIENT_REVISION_2 (2) [2019/08/03 07:14:24.156189, 6, pid=23639, effective(967001000, 967001000), real(967001000, 0), class=rpc_srv] ../../source3/rpc_server/rpc_handles.c:339(find_policy_by_hnd_internal) Found policy hnd[0] [0000] 00 00 00 00 4C 00 00 00 00 00 00 00 45 5D 30 18 ....L... ....E]0. [0010] 57 5C 00 00 W\.. [2019/08/03 07:14:24.156228, 4, pid=23639, effective(967001000, 967001000), real(967001000, 0)] ../../source3/smbd/sec_ctx.c:215(push_sec_ctx) push_sec_ctx(967001000, 967001000) : sec_ctx_stack_ndx = 2 [2019/08/03 07:14:24.156246, 4, pid=23639, effective(967001000, 967001000), real(967001000, 0)] ../../source3/smbd/uid.c:552(push_conn_ctx) push_conn_ctx(0) : conn_ctx_stack_ndx = 0 [2019/08/03 07:14:24.156259, 4, pid=23639, effective(967001000, 967001000), real(967001000, 0)] ../../source3/smbd/sec_ctx.c:319(set_sec_ctx_internal) setting sec ctx (0, 0) - sec_ctx_stack_ndx = 2 [2019/08/03 07:14:24.156273, 5, pid=23639, effective(967001000, 967001000), real(967001000, 0)] ../../libcli/security/security_token.c:53(security_token_debug) Security token: (NULL) [2019/08/03 07:14:24.156285, 5, pid=23639, effective(967001000, 967001000), real(967001000, 0)] ../../source3/auth/token_util.c:865(debug_unix_user_token) UNIX token of user 0 Primary group is 0 and contains 0 supplementary groups [2019/08/03 07:14:24.156311, 5, pid=23639, effective(0, 0), real(0, 0), class=rpc_srv] ../../source3/rpc_server/lsa/srv_lsa_nt.c:244(lookup_lsa_sids) lookup_lsa_sids: looking up name XS\ab [2019/08/03 07:14:24.156327, 10, pid=23639, effective(0, 0), real(0, 0)] ../../source3/passdb/lookup_sid.c:112(lookup_name) lookup_name: XS\ab => domain=[XS], name=[ab] [2019/08/03 07:14:24.156340, 10, pid=23639, effective(0, 0), real(0, 0)] ../../source3/passdb/lookup_sid.c:114(lookup_name) lookup_name: flags = 0x00 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14091 Signed-off-by: Alexander Bokovoy Reviewed-by: Andreas Schneider (cherry picked from commit 685bb03de6ab733590831d1df4f5fd60d2ac427d) --- source3/passdb/lookup_sid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index 6ab72e57838..c31a9e48739 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -113,7 +113,7 @@ bool lookup_name(TALLOC_CTX *mem_ctx, full_name, domain, name)); DEBUG(10, ("lookup_name: flags = 0x0%x\n", flags)); - if ((flags & LOOKUP_NAME_DOMAIN) && + if (((flags & LOOKUP_NAME_DOMAIN) || (flags == 0)) && strequal(domain, get_global_sam_name())) { -- 2.17.1 From 38876ad4ef46fc3cf6a12329236918a87c2e2c65 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Sat, 10 Aug 2019 11:53:12 +0300 Subject: [PATCH 023/376] smbtorture: extend rpc.lsa to lookup machine over forest-wide LookupNames Add a simple test to resolve DOMAIN\MACHINE$ via LSA LookupNames3 using LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2 level. This level would pass zero lookup flags to lookup_name(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14091 Signed-off-by: Alexander Bokovoy Reviewed-by: Andreas Schneider Autobuild-User(master): Alexander Bokovoy Autobuild-Date(master): Wed Aug 14 13:07:42 UTC 2019 on sn-devel-184 (cherry picked from commit 4d276a93fc624dc04d880f5b4157f272d3555be6) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Mon Aug 19 12:36:22 UTC 2019 on sn-devel-184 --- source4/torture/rpc/lsa.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c index fdbfcbffc16..0ce113feb5d 100644 --- a/source4/torture/rpc/lsa.c +++ b/source4/torture/rpc/lsa.c @@ -4819,7 +4819,7 @@ static bool test_QueryInfoPolicyCalls( bool version2, || i == LSA_POLICY_INFO_DNS_INT)) { /* Let's look up some of these names */ - struct lsa_TransNameArray tnames; + struct lsa_TransNameArray tnames, dnames; tnames.count = 14; tnames.names = talloc_zero_array(tctx, struct lsa_TranslatedName, tnames.count); tnames.names[0].name.string = info->dns.name.string; @@ -4852,6 +4852,12 @@ static bool test_QueryInfoPolicyCalls( bool version2, tnames.names[13].sid_type = SID_NAME_USER; ret &= test_LookupNames(b, tctx, handle, LSA_LOOKUP_NAMES_ALL, &tnames); + /* Try to use in-forest search for the test machine */ + dnames.count = 1; + dnames.names = talloc_zero_array(tctx, struct lsa_TranslatedName, dnames.count); + dnames.names[0].name.string = talloc_asprintf(tctx, "%s\\"TEST_MACHINENAME "$", info->dns.name.string); + dnames.names[0].sid_type = SID_NAME_USER; + ret &= test_LookupNames(b, tctx, handle, LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2, &dnames); } } -- 2.17.1 From fab20658b9a4d04e2eab89d95b6eb7e04187424d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 4 Aug 2019 12:10:03 +0200 Subject: [PATCH 024/376] tdb: Rename tdb_oob() to tdb_notrans_oob() tdb_oob() will become a public function encapsulating the pointer dereferences. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit 885ba572efaac6c20388b8e119315c837e8f5236) --- lib/tdb/common/io.c | 6 +++--- lib/tdb/test/run-3G-file.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c index df460176159..06492b1407d 100644 --- a/lib/tdb/common/io.c +++ b/lib/tdb/common/io.c @@ -136,8 +136,8 @@ static int tdb_fstat(struct tdb_context *tdb, struct stat *buf) see if the database has been expanded by someone else and expand if necessary */ -static int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, - int probe) +static int tdb_notrans_oob( + struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe) { struct stat st; if (len + off < len) { @@ -782,7 +782,7 @@ static const struct tdb_methods io_methods = { tdb_read, tdb_write, tdb_next_hash_chain, - tdb_oob, + tdb_notrans_oob, tdb_expand_file, }; diff --git a/lib/tdb/test/run-3G-file.c b/lib/tdb/test/run-3G-file.c index 748c972284a..79e291b294e 100644 --- a/lib/tdb/test/run-3G-file.c +++ b/lib/tdb/test/run-3G-file.c @@ -48,7 +48,7 @@ static const struct tdb_methods large_io_methods = { tdb_read, tdb_write, tdb_next_hash_chain, - tdb_oob, + tdb_notrans_oob, tdb_expand_file_sparse }; -- 2.17.1 From 6312223d6e609d629dfc7914d62bf80ced584c6b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 4 Aug 2019 12:15:14 +0200 Subject: [PATCH 025/376] tdb: Introduce tdb_oob() Initially just encapsulate the pointer dereferences Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit 5a388453e0cb038fa3ed5fb46f972470f7793566) --- lib/tdb/common/check.c | 6 +++--- lib/tdb/common/freelist.c | 2 +- lib/tdb/common/io.c | 22 ++++++++++++++-------- lib/tdb/common/open.c | 6 +++--- lib/tdb/common/rescue.c | 4 ++-- lib/tdb/common/tdb_private.h | 1 + lib/tdb/common/transaction.c | 2 +- lib/tdb/common/traverse.c | 3 +-- 8 files changed, 26 insertions(+), 20 deletions(-) diff --git a/lib/tdb/common/check.c b/lib/tdb/common/check.c index 3a5c8b8ba94..d7741f6b2f9 100644 --- a/lib/tdb/common/check.c +++ b/lib/tdb/common/check.c @@ -94,7 +94,7 @@ static bool tdb_check_record(struct tdb_context *tdb, off, rec->next)); goto corrupt; } - if (tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0)) + if (tdb_oob(tdb, rec->next, sizeof(*rec), 0)) goto corrupt; /* Check rec_len: similar to rec->next, implies next record. */ @@ -112,7 +112,7 @@ static bool tdb_check_record(struct tdb_context *tdb, goto corrupt; } /* OOB allows "right at the end" access, so this works for last rec. */ - if (tdb->methods->tdb_oob(tdb, off, sizeof(*rec)+rec->rec_len, 0)) + if (tdb_oob(tdb, off, sizeof(*rec)+rec->rec_len, 0)) goto corrupt; /* Check tailer. */ @@ -362,7 +362,7 @@ _PUBLIC_ int tdb_check(struct tdb_context *tdb, } /* Make sure we know true size of the underlying file. */ - tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1); + tdb_oob(tdb, tdb->map_size, 1, 1); /* Header must be OK: also gets us the recovery ptr, if any. */ if (!tdb_check_header(tdb, &recovery_start)) diff --git a/lib/tdb/common/freelist.c b/lib/tdb/common/freelist.c index 37a4c168533..046c747cf9b 100644 --- a/lib/tdb/common/freelist.c +++ b/lib/tdb/common/freelist.c @@ -50,7 +50,7 @@ int tdb_rec_free_read(struct tdb_context *tdb, tdb_off_t off, struct tdb_record rec->magic, off)); return -1; } - if (tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0) != 0) + if (tdb_oob(tdb, rec->next, sizeof(*rec), 0) != 0) return -1; return 0; } diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c index 06492b1407d..f3ea7bf9856 100644 --- a/lib/tdb/common/io.c +++ b/lib/tdb/common/io.c @@ -216,7 +216,7 @@ static int tdb_write(struct tdb_context *tdb, tdb_off_t off, return -1; } - if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0) + if (tdb_oob(tdb, off, len, 0) != 0) return -1; if (tdb->map_ptr) { @@ -271,7 +271,7 @@ void *tdb_convert(void *buf, uint32_t size) static int tdb_read(struct tdb_context *tdb, tdb_off_t off, void *buf, tdb_len_t len, int cv) { - if (tdb->methods->tdb_oob(tdb, off, len, 0) != 0) { + if (tdb_oob(tdb, off, len, 0) != 0) { return -1; } @@ -596,7 +596,7 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size) } /* must know about any previous expansions by another process */ - tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1); + tdb_oob(tdb, tdb->map_size, 1, 1); /* * Note: that we don't care about tdb->hdr_ofs != 0 here @@ -662,6 +662,12 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size) return -1; } +int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe) +{ + int ret = tdb->methods->tdb_oob(tdb, off, len, probe); + return ret; +} + /* read/write a tdb_off_t */ int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d) { @@ -714,7 +720,7 @@ int tdb_parse_data(struct tdb_context *tdb, TDB_DATA key, * Optimize by avoiding the malloc/memcpy/free, point the * parser directly at the mmap area. */ - if (tdb->methods->tdb_oob(tdb, offset, len, 0) != 0) { + if (tdb_oob(tdb, offset, len, 0) != 0) { return -1; } data.dptr = offset + (unsigned char *)tdb->map_ptr; @@ -756,20 +762,20 @@ int tdb_rec_read(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *r return -1; } - ret = tdb->methods->tdb_oob(tdb, offset, rec->key_len, 1); + ret = tdb_oob(tdb, offset, rec->key_len, 1); if (ret == -1) { return -1; } - ret = tdb->methods->tdb_oob(tdb, offset, rec->data_len, 1); + ret = tdb_oob(tdb, offset, rec->data_len, 1); if (ret == -1) { return -1; } - ret = tdb->methods->tdb_oob(tdb, offset, rec->rec_len, 1); + ret = tdb_oob(tdb, offset, rec->rec_len, 1); if (ret == -1) { return -1; } - return tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 0); + return tdb_oob(tdb, rec->next, sizeof(*rec), 0); } int tdb_rec_write(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec) diff --git a/lib/tdb/common/open.c b/lib/tdb/common/open.c index dd5783ef8bc..f7f65b0e237 100644 --- a/lib/tdb/common/open.c +++ b/lib/tdb/common/open.c @@ -655,7 +655,7 @@ _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int td * As this skips tdb->hdr_ofs. */ tdb->map_size = 0; - ret = tdb->methods->tdb_oob(tdb, 0, 1, 0); + ret = tdb_oob(tdb, 0, 1, 0); if (ret == -1) { errno = EIO; goto fail; @@ -677,7 +677,7 @@ _PUBLIC_ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int td goto fail; } - ret = tdb->methods->tdb_oob(tdb, FREELIST_TOP, 4*tdb->hash_size, 1); + ret = tdb_oob(tdb, FREELIST_TOP, 4*tdb->hash_size, 1); if (ret == -1) { TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: " "hash size %"PRIu32" does not fit\n", tdb->hash_size)); @@ -895,7 +895,7 @@ static int tdb_reopen_internal(struct tdb_context *tdb, bool active_lock) * As this skips tdb->hdr_ofs. */ tdb->map_size = 0; - if (tdb->methods->tdb_oob(tdb, 0, 1, 0) != 0) { + if (tdb_oob(tdb, 0, 1, 0) != 0) { goto fail; } #endif /* fake pread or pwrite */ diff --git a/lib/tdb/common/rescue.c b/lib/tdb/common/rescue.c index e608db41dea..7a85ebc9311 100644 --- a/lib/tdb/common/rescue.c +++ b/lib/tdb/common/rescue.c @@ -60,7 +60,7 @@ static bool looks_like_valid_record(struct tdb_context *tdb, if (rec->next > 0 && rec->next < TDB_DATA_START(tdb->hash_size)) return false; - if (tdb->methods->tdb_oob(tdb, rec->next, sizeof(*rec), 1)) + if (tdb_oob(tdb, rec->next, sizeof(*rec), 1)) return false; key->dsize = rec->key_len; @@ -228,7 +228,7 @@ _PUBLIC_ int tdb_rescue(struct tdb_context *tdb, } /* Make sure we know true size of the underlying file. */ - tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1); + tdb_oob(tdb, tdb->map_size, 1, 1); /* Suppress logging, since we anticipate errors. */ tdb->log.log_fn = logging_suppressed; diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h index 42aaac62f59..2bed8200f94 100644 --- a/lib/tdb/common/tdb_private.h +++ b/lib/tdb/common/tdb_private.h @@ -304,6 +304,7 @@ void *tdb_convert(void *buf, uint32_t size); int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); tdb_off_t tdb_allocate(struct tdb_context *tdb, int hash, tdb_len_t length, struct tdb_record *rec); +int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe); int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d); int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d); int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off); diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c index e9b0b26ea59..b22624820d7 100644 --- a/lib/tdb/common/transaction.c +++ b/lib/tdb/common/transaction.c @@ -524,7 +524,7 @@ static int _tdb_transaction_start(struct tdb_context *tdb, /* make sure we know about any file expansions already done by anyone else */ - tdb->methods->tdb_oob(tdb, tdb->map_size, 1, 1); + tdb_oob(tdb, tdb->map_size, 1, 1); tdb->transaction->old_map_size = tdb->map_size; /* finally hook the io methods, replacing them with diff --git a/lib/tdb/common/traverse.c b/lib/tdb/common/traverse.c index 54a69dc8d03..d69e7dff285 100644 --- a/lib/tdb/common/traverse.c +++ b/lib/tdb/common/traverse.c @@ -453,8 +453,7 @@ _PUBLIC_ int tdb_traverse_chain(struct tdb_context *tdb, if ((tdb->transaction == NULL) && (tdb->map_ptr != NULL)) { - ret = tdb->methods->tdb_oob( - tdb, key_ofs, full_len, 0); + ret = tdb_oob(tdb, key_ofs, full_len, 0); if (ret == -1) { goto fail; } -- 2.17.1 From 3325a4d4146d5793b1ae6a7b7a502c52a489ac59 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 4 Aug 2019 12:18:19 +0200 Subject: [PATCH 026/376] tdb: Speed up tdb_oob() This is common between both implementations of tdb_oob(). It's faster if we don't have to dereference function pointers. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit 897bffa8166f643eb9063a848bb0c02455663317) --- lib/tdb/common/io.c | 13 ++++++++++++- lib/tdb/common/transaction.c | 5 +++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c index f3ea7bf9856..28e808143a2 100644 --- a/lib/tdb/common/io.c +++ b/lib/tdb/common/io.c @@ -150,6 +150,11 @@ static int tdb_notrans_oob( return -1; } + /* + * This duplicates functionality from tdb_oob(). Don't remove: + * we still have direct callers of tdb->methods->tdb_oob() + * inside transaction.c. + */ if (off + len <= tdb->map_size) return 0; if (tdb->flags & TDB_INTERNAL) { @@ -664,7 +669,13 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size) int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe) { - int ret = tdb->methods->tdb_oob(tdb, off, len, probe); + int ret; + + if (likely((off + len >= off) && (off + len <= tdb->map_size))) { + return 0; + } + + ret = tdb->methods->tdb_oob(tdb, off, len, probe); return ret; } diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c index b22624820d7..4f8d1f8cdcc 100644 --- a/lib/tdb/common/transaction.c +++ b/lib/tdb/common/transaction.c @@ -378,6 +378,11 @@ static void transaction_next_hash_chain(struct tdb_context *tdb, uint32_t *chain static int transaction_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe) { + /* + * This duplicates functionality from tdb_oob(). Don't remove: + * we still have direct callers of tdb->methods->tdb_oob() + * inside transaction.c. + */ if (off + len >= off && off + len <= tdb->map_size) { return 0; } -- 2.17.1 From afd6b77bb849bdcfa30513626c61a7aade7d88e2 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Sun, 4 Aug 2019 18:26:05 +0200 Subject: [PATCH 027/376] tdb: Inline the common part of tdb_oob When you set in tdbtorture.c to make it more similar to locking.tdb use, bin/tdbtorture -m -n 1 -l 100000 -s becomes twice as fast. This is a pretty extreme case, but all other tests that I did improve significantly as well. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison (cherry picked from commit f5735e2c666a5a494131c1d25f7ba5c7fbeae923) --- lib/tdb/common/io.c | 10 ++-------- lib/tdb/common/tdb_private.h | 14 +++++++++++++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/tdb/common/io.c b/lib/tdb/common/io.c index 28e808143a2..0de0dabd827 100644 --- a/lib/tdb/common/io.c +++ b/lib/tdb/common/io.c @@ -667,15 +667,9 @@ int tdb_expand(struct tdb_context *tdb, tdb_off_t size) return -1; } -int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe) +int _tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe) { - int ret; - - if (likely((off + len >= off) && (off + len <= tdb->map_size))) { - return 0; - } - - ret = tdb->methods->tdb_oob(tdb, off, len, probe); + int ret = tdb->methods->tdb_oob(tdb, off, len, probe); return ret; } diff --git a/lib/tdb/common/tdb_private.h b/lib/tdb/common/tdb_private.h index 2bed8200f94..29790434211 100644 --- a/lib/tdb/common/tdb_private.h +++ b/lib/tdb/common/tdb_private.h @@ -304,7 +304,19 @@ void *tdb_convert(void *buf, uint32_t size); int tdb_free(struct tdb_context *tdb, tdb_off_t offset, struct tdb_record *rec); tdb_off_t tdb_allocate(struct tdb_context *tdb, int hash, tdb_len_t length, struct tdb_record *rec); -int tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe); + +int _tdb_oob(struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe); + +static inline int tdb_oob( + struct tdb_context *tdb, tdb_off_t off, tdb_len_t len, int probe) +{ + if (likely((off + len >= off) && (off + len <= tdb->map_size))) { + return 0; + } + return _tdb_oob(tdb, off, len, probe); +} + + int tdb_ofs_read(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d); int tdb_ofs_write(struct tdb_context *tdb, tdb_off_t offset, tdb_off_t *d); int tdb_lock_record(struct tdb_context *tdb, tdb_off_t off); -- 2.17.1 From c14427253e8cb4aab951ded527258e6f67fc4452 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 20 Aug 2019 14:55:27 +0200 Subject: [PATCH 028/376] tdb: Release tdb 1.4.2 * Build fixes * Improve the performance by inlining the tdb_oob() checks Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Tue Aug 20 14:45:41 UTC 2019 on sn-devel-184 (cherry picked from commit 60cba7b3a17104da1543d59609f50c6638880dd1) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Wed Aug 21 09:57:08 UTC 2019 on sn-devel-184 --- lib/tdb/ABI/tdb-1.4.2.sigs | 73 ++++++++++++++++++++++++++++++++++++++ lib/tdb/wscript | 2 +- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 lib/tdb/ABI/tdb-1.4.2.sigs diff --git a/lib/tdb/ABI/tdb-1.4.2.sigs b/lib/tdb/ABI/tdb-1.4.2.sigs new file mode 100644 index 00000000000..e2b0427c347 --- /dev/null +++ b/lib/tdb/ABI/tdb-1.4.2.sigs @@ -0,0 +1,73 @@ +tdb_add_flags: void (struct tdb_context *, unsigned int) +tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) +tdb_chainlock: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) +tdb_chainunlock: int (struct tdb_context *, TDB_DATA) +tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) +tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_close: int (struct tdb_context *) +tdb_delete: int (struct tdb_context *, TDB_DATA) +tdb_dump_all: void (struct tdb_context *) +tdb_enable_seqnum: void (struct tdb_context *) +tdb_error: enum TDB_ERROR (struct tdb_context *) +tdb_errorstr: const char *(struct tdb_context *) +tdb_exists: int (struct tdb_context *, TDB_DATA) +tdb_fd: int (struct tdb_context *) +tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) +tdb_firstkey: TDB_DATA (struct tdb_context *) +tdb_freelist_size: int (struct tdb_context *) +tdb_get_flags: int (struct tdb_context *) +tdb_get_logging_private: void *(struct tdb_context *) +tdb_get_seqnum: int (struct tdb_context *) +tdb_hash_size: int (struct tdb_context *) +tdb_increment_seqnum_nonblock: void (struct tdb_context *) +tdb_jenkins_hash: unsigned int (TDB_DATA *) +tdb_lock_nonblock: int (struct tdb_context *, int, int) +tdb_lockall: int (struct tdb_context *) +tdb_lockall_mark: int (struct tdb_context *) +tdb_lockall_nonblock: int (struct tdb_context *) +tdb_lockall_read: int (struct tdb_context *) +tdb_lockall_read_nonblock: int (struct tdb_context *) +tdb_lockall_unmark: int (struct tdb_context *) +tdb_log_fn: tdb_log_func (struct tdb_context *) +tdb_map_size: size_t (struct tdb_context *) +tdb_name: const char *(struct tdb_context *) +tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) +tdb_null: dptr = 0xXXXX, dsize = 0 +tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) +tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) +tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_printfreelist: int (struct tdb_context *) +tdb_remove_flags: void (struct tdb_context *, unsigned int) +tdb_reopen: int (struct tdb_context *) +tdb_reopen_all: int (int) +tdb_repack: int (struct tdb_context *) +tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_runtime_check_for_robust_mutexes: bool (void) +tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) +tdb_set_max_dead: void (struct tdb_context *, int) +tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) +tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) +tdb_storev: int (struct tdb_context *, TDB_DATA, const TDB_DATA *, int, int) +tdb_summary: char *(struct tdb_context *) +tdb_transaction_active: bool (struct tdb_context *) +tdb_transaction_cancel: int (struct tdb_context *) +tdb_transaction_commit: int (struct tdb_context *) +tdb_transaction_prepare_commit: int (struct tdb_context *) +tdb_transaction_start: int (struct tdb_context *) +tdb_transaction_start_nonblock: int (struct tdb_context *) +tdb_transaction_write_lock_mark: int (struct tdb_context *) +tdb_transaction_write_lock_unmark: int (struct tdb_context *) +tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) +tdb_traverse_chain: int (struct tdb_context *, unsigned int, tdb_traverse_func, void *) +tdb_traverse_key_chain: int (struct tdb_context *, TDB_DATA, tdb_traverse_func, void *) +tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) +tdb_unlock: int (struct tdb_context *, int, int) +tdb_unlockall: int (struct tdb_context *) +tdb_unlockall_read: int (struct tdb_context *) +tdb_validate_freelist: int (struct tdb_context *, int *) +tdb_wipe_all: int (struct tdb_context *) diff --git a/lib/tdb/wscript b/lib/tdb/wscript index ece44f82e33..1ab0e8d334a 100644 --- a/lib/tdb/wscript +++ b/lib/tdb/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'tdb' -VERSION = '1.4.1' +VERSION = '1.4.2' import sys, os -- 2.17.1 From 521240aa3728d61e8b768c6e5f20146afaf97e2f Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Wed, 21 Aug 2019 12:34:58 +0200 Subject: [PATCH 029/376] VERSION: Disable GIT_SNAPSHOT for the 4.11.0rc2 release. Signed-off-by: Karolin Seeger --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c70b521219c..12f04435907 100644 --- a/VERSION +++ b/VERSION @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE=2 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=yes +SAMBA_VERSION_IS_GIT_SNAPSHOT=no ######################################################## # This is for specifying a release nickname # -- 2.17.1 From ea38596181c8e64f87019d7cfa48b0e0dc225e70 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Wed, 21 Aug 2019 12:36:23 +0200 Subject: [PATCH 030/376] VERSION: Bump version up to 4.11.0rc3... and re-enable GIT_SNAPSHOT. Signed-off-by: Karolin Seeger --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 12f04435907..67ae2000ebf 100644 --- a/VERSION +++ b/VERSION @@ -87,7 +87,7 @@ SAMBA_VERSION_PRE_RELEASE= # e.g. SAMBA_VERSION_RC_RELEASE=1 # # -> "3.0.0rc1" # ######################################################## -SAMBA_VERSION_RC_RELEASE=2 +SAMBA_VERSION_RC_RELEASE=3 ######################################################## # To mark SVN snapshots this should be set to 'yes' # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE=2 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname # -- 2.17.1 From 72d79334a53917bd3ee6521bcea2a551906712da Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Fri, 7 Jun 2019 12:55:32 -0700 Subject: [PATCH 031/376] Revert "nfs4acl: Fix owner mapping with ID_TYPE_BOTH" This reverts commit 5d4f7bfda579cecb123cfb1d7130688f1d1c98b7. That patch broke the case with ID_TYPE_BOTH where a file is owned by a group (e.g. using autorid and having a file owned by BUILTIN\Administrators). In this case, the ACE entry for the group gets mapped a to a user ACL entry and the group no longer has access (as in the user's token the group is not mapped to a uid). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 42bd3a72a2525aa8a918f4bf7067b30ce8e0e197) --- source3/modules/nfs4_acls.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 7776caa16d2..6db5a6db6d9 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -723,14 +723,7 @@ static bool smbacl4_fill_ace4( uid_t uid; gid_t gid; - /* - * ID_TYPE_BOTH returns both uid and gid. Explicitly - * check for ownerUID to allow the mapping of the - * owner to a special entry in this idmap config. - */ - if (sid_to_uid(&ace_nt->trustee, &uid) && uid == ownerUID) { - ace_v4->who.uid = uid; - } else if (sid_to_gid(&ace_nt->trustee, &gid)) { + if (sid_to_gid(&ace_nt->trustee, &gid)) { ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; ace_v4->who.gid = gid; } else if (sid_to_uid(&ace_nt->trustee, &uid)) { -- 2.17.1 From 9e82d8ae7fa94228656e9a82d5a7d41d5cb0a4e3 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 11 Jun 2019 16:15:10 -0700 Subject: [PATCH 032/376] nfs4_acls: Remove fsp from smbacl4_win2nfs4 Only the information whether the ACL is for a file or a directory is required. Replacing the fsp with a flag is clearer and allows for unit testing of the mapping functions. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit a06486bb110d04a90b66a0bca4b1b600ef3c0ebf) --- source3/modules/nfs4_acls.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 6db5a6db6d9..5543b3a7f58 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -648,7 +648,7 @@ static SMB_ACE4PROP_T *smbacl4_find_equal_special( static bool smbacl4_fill_ace4( - const struct smb_filename *filename, + bool is_directory, const struct smbacl4_vfs_params *params, uid_t ownerUID, gid_t ownerGID, @@ -670,8 +670,7 @@ static bool smbacl4_fill_ace4( ace_nt->flags); /* remove inheritance flags on files */ - if (VALID_STAT(filename->st) && - !S_ISDIR(filename->st.st_ex_mode)) { + if (!is_directory) { DEBUG(10, ("Removing inheritance flags from a file\n")); ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE| SMB_ACE4_DIRECTORY_INHERIT_ACE| @@ -732,9 +731,8 @@ static bool smbacl4_fill_ace4( &global_sid_Unix_NFS) == 0) { return false; } else { - DEBUG(1, ("nfs4_acls.c: file [%s]: could not " + DEBUG(1, ("nfs4_acls.c: could not " "convert %s to uid or gid\n", - filename->base_name, dom_sid_str_buf(&ace_nt->trustee, &buf))); return false; } @@ -855,7 +853,7 @@ static int smbacl4_substitute_simple( static struct SMB4ACL_T *smbacl4_win2nfs4( TALLOC_CTX *mem_ctx, - const files_struct *fsp, + bool is_directory, const struct security_acl *dacl, const struct smbacl4_vfs_params *pparams, uid_t ownerUID, @@ -864,7 +862,6 @@ static struct SMB4ACL_T *smbacl4_win2nfs4( { struct SMB4ACL_T *theacl; uint32_t i; - const char *filename = fsp->fsp_name->base_name; DEBUG(10, ("smbacl4_win2nfs4 invoked\n")); @@ -876,12 +873,11 @@ static struct SMB4ACL_T *smbacl4_win2nfs4( SMB_ACE4PROP_T ace_v4; bool addNewACE = true; - if (!smbacl4_fill_ace4(fsp->fsp_name, pparams, + if (!smbacl4_fill_ace4(is_directory, pparams, ownerUID, ownerGID, dacl->aces + i, &ace_v4)) { struct dom_sid_buf buf; - DEBUG(3, ("Could not fill ace for file %s, SID %s\n", - filename, + DEBUG(3, ("Could not fill ace for file, SID %s\n", dom_sid_str_buf(&((dacl->aces+i)->trustee), &buf))); continue; @@ -916,7 +912,7 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp, { struct smbacl4_vfs_params params; struct SMB4ACL_T *theacl = NULL; - bool result; + bool result, is_directory; SMB_STRUCT_STAT sbuf; bool set_acl_as_root = false; @@ -951,6 +947,8 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp, return map_nt_error_from_unix(errno); } + is_directory = S_ISDIR(sbuf.st_ex_mode); + if (pparams->do_chown) { /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */ NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID, @@ -998,7 +996,7 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp, return NT_STATUS_OK; } - theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, pparams, + theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams, sbuf.st_ex_uid, sbuf.st_ex_gid); if (!theacl) { TALLOC_FREE(frame); -- 2.17.1 From 88b0461ca0d120d39e10a8765d2f25429ef2faab Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:22:13 -0700 Subject: [PATCH 033/376] selftest: Start implementing unit test for nfs4_acls Existing smbtorture tests set and query ACLs through SMB, only working with the DACLs in the Security Descriptors, but never check the NFSv4 ACL representation. This patch introduces a unit test to verify the mapping between between Security Descriptors and NFSv4 ACLs. As the mapping code queries id mappings, the id mapping cache is first primed with the mappings used by the tests and those mappings are removed again during teardown. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 8fb906a1860452a320c79ac87917a97303729c19) --- source3/modules/test_nfs4_acls.c | 136 +++++++++++++++++++++++++++++++ source3/modules/wscript_build | 5 ++ source3/selftest/tests.py | 4 + 3 files changed, 145 insertions(+) create mode 100644 source3/modules/test_nfs4_acls.c diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c new file mode 100644 index 00000000000..557f27c7428 --- /dev/null +++ b/source3/modules/test_nfs4_acls.c @@ -0,0 +1,136 @@ +/* + * Unix SMB/CIFS implementation. + * + * Unit test for NFS4 ACL handling + * + * Copyright (C) Christof Schmitt 2019 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "nfs4_acls.c" +#include "librpc/gen_ndr/idmap.h" +#include "idmap_cache.h" +#include + +struct test_sids { + const char *sid_str; + struct unixid unix_id; +} test_sids[] = { + { "S-1-5-2-123-456-789-100", { 1000, ID_TYPE_UID }}, + { "S-1-5-2-123-456-789-101", { 1001, ID_TYPE_GID }}, + { "S-1-5-2-123-456-789-102", { 1002, ID_TYPE_BOTH }}, + { SID_CREATOR_OWNER, { 1003, ID_TYPE_UID }}, + { SID_CREATOR_GROUP, { 1004, ID_TYPE_GID }}, + { "S-1-5-2-123-456-789-103", { 1000, ID_TYPE_GID }}, + { "S-1-5-2-123-456-789-104", { 1005, ID_TYPE_BOTH }}, + { "S-1-5-2-123-456-789-105", { 1006, ID_TYPE_BOTH }}, + { "S-1-5-2-123-456-789-106", { 1007, ID_TYPE_BOTH }}, +}; + +static int group_setup(void **state) +{ + struct dom_sid *sids = NULL; + int i; + + sids = talloc_array(NULL, struct dom_sid, ARRAY_SIZE(test_sids)); + assert_non_null(sids); + + for (i = 0; i < ARRAY_SIZE(test_sids); i++) { + assert_true(dom_sid_parse(test_sids[i].sid_str, &sids[i])); + idmap_cache_set_sid2unixid(&sids[i], &test_sids[i].unix_id); + } + + *state = sids; + + return 0; + +} + +static int group_teardown(void **state) +{ + struct dom_sid *sids = *state; + int i; + + for (i = 0; i < ARRAY_SIZE(test_sids); i++) { + assert_true(idmap_cache_del_sid(&sids[i])); + } + + TALLOC_FREE(sids); + *state = NULL; + + return 0; +} + +/* + * Run this as first test to verify that the id mappings used by other + * tests are available in the cache. + */ +static void test_cached_id_mappings(void **state) +{ + struct dom_sid *sids = *state; + int i; + + for (i = 0; i < ARRAY_SIZE(test_sids); i++) { + struct dom_sid *sid = &sids[i]; + struct unixid *unix_id = &test_sids[i].unix_id; + uid_t uid; + gid_t gid; + + switch(unix_id->type) { + case ID_TYPE_UID: + assert_true(sid_to_uid(sid, &uid)); + assert_int_equal(uid, unix_id->id); + assert_false(sid_to_gid(sid, &gid)); + break; + case ID_TYPE_GID: + assert_false(sid_to_uid(sid, &uid)); + assert_true(sid_to_gid(sid, &gid)); + assert_int_equal(gid, unix_id->id); + break; + case ID_TYPE_BOTH: + assert_true(sid_to_uid(sid, &uid)); + assert_int_equal(uid, unix_id->id); + assert_true(sid_to_gid(sid, &gid)); + assert_int_equal(gid, unix_id->id); + break; + default: + fail_msg("Unknown id type %d\n", unix_id->type); + break; + } + } +} + +int main(int argc, char **argv) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_cached_id_mappings), + }; + + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); + + if (argc != 2) { + print_error("Usage: %s smb.conf\n", argv[0]); + exit(1); + } + + /* + * Initialize enough of the Samba internals to have the + * mappings tests work. + */ + talloc_stackframe(); + lp_load_global(argv[1]); + + return cmocka_run_group_tests(tests, group_setup, group_teardown); +} diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build index 5e0047da917..80b0ce9ff90 100644 --- a/source3/modules/wscript_build +++ b/source3/modules/wscript_build @@ -4,6 +4,11 @@ bld.SAMBA3_SUBSYSTEM('NFS4_ACLS', source='nfs4_acls.c', deps='samba-util tdb') +bld.SAMBA3_BINARY('test_nfs4_acls', + source='test_nfs4_acls.c', + deps='smbd_base cmocka', + install=False) + bld.SAMBA3_SUBSYSTEM('vfs_acl_common', source='vfs_acl_common.c') diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 78f58bdb30c..9569aa9ae00 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -427,6 +427,10 @@ if with_pthreadpool: "script/tests/test_libwbclient_threads.sh"), "$DOMAIN", "$DC_USERNAME"]) +plantestsuite("samba3.test_nfs4_acl", "none", + [os.path.join(bindir(), "test_nfs4_acls"), + "$SMB_CONF_PATH"]) + plantestsuite( "samba3.resolvconf", "none", [os.path.join(samba3srcdir, "script/tests/test_resolvconf.sh")]) -- 2.17.1 From 526da3f215a12dca398ad6c615541e5edb359dae Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:23:40 -0700 Subject: [PATCH 034/376] test_nfs4_acls: Add tests for mapping of empty ACLs This is a fairly simple test that ensures the mapping of empty ACLs (without any ACL entries) is always done the same way. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 00f494b25f4e1d1aecf6191523e30f20a90b1e4f) --- source3/modules/test_nfs4_acls.c | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 557f27c7428..18322afb4a0 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -112,10 +112,63 @@ static void test_cached_id_mappings(void **state) } } +static void test_empty_nfs4_to_dacl(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + struct SMB4ACL_T *nfs4_acl; + struct security_ace *dacl_aces; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[0], &sids[1], false, + &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 0); + assert_null(dacl_aces); + + TALLOC_FREE(frame); +} + +static void test_empty_dacl_to_nfs4(void **state) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct SMB4ACL_T *nfs4_acl; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, 0, NULL); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, false, dacl, ¶ms, 1001, 1002); + + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 0); + assert_null(smb_first_ace4(nfs4_acl)); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_cached_id_mappings), + cmocka_unit_test(test_empty_nfs4_to_dacl), + cmocka_unit_test(test_empty_dacl_to_nfs4), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 4120b8dcbe8e8de5cb4db7e09a8916f4ab4d4493 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:25:33 -0700 Subject: [PATCH 035/376] test_nfs4_acls: Add tests for mapping of ACL types Add testcases for mapping the type field (ALLOW or DENY) between NFSv4 ACLs and security descriptors. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit dd5934797526ebb4c6f3027a809401dad3abf701) --- source3/modules/test_nfs4_acls.c | 107 +++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 18322afb4a0..b29714d23e3 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -163,12 +163,119 @@ static void test_empty_dacl_to_nfs4(void **state) assert_null(smb_first_ace4(nfs4_acl)); } +struct ace_dacl_type_mapping { + uint32_t nfs4_type; + enum security_ace_type dacl_type; +} ace_dacl_type_mapping[] = { + { SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, SEC_ACE_TYPE_ACCESS_ALLOWED }, + { SMB_ACE4_ACCESS_DENIED_ACE_TYPE, SEC_ACE_TYPE_ACCESS_DENIED }, +}; + +static void test_acl_type_nfs4_to_dacl(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(ace_dacl_type_mapping); i++) { + struct SMB4ACL_T *nfs4_acl; + SMB_ACE4PROP_T nfs4_ace; + struct security_ace *dacl_aces; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .who.uid = 1000, + .aceType = ace_dacl_type_mapping[i].nfs4_type, + .aceFlags = 0, + .aceMask = SMB_ACE4_READ_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[2], &sids[3], false, + &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 1); + assert_non_null(dacl_aces); + + assert_int_equal(dacl_aces[0].type, + ace_dacl_type_mapping[i].dacl_type); + assert_int_equal(dacl_aces[0].flags, 0); + assert_int_equal(dacl_aces[0].access_mask, SEC_FILE_READ_DATA); + assert_true(dom_sid_equal(&dacl_aces[0].trustee, &sids[0])); + } + + TALLOC_FREE(frame); +} + +static void test_acl_type_dacl_to_nfs4(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(ace_dacl_type_mapping); i++) { + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + struct security_ace dacl_aces[1]; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + init_sec_ace(&dacl_aces[0], &sids[0], + ace_dacl_type_mapping[i].dacl_type, + SEC_FILE_READ_DATA, 0); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, false, dacl, ¶ms, + 101, 102); + + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 1); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, 0); + assert_int_equal(nfs4_ace->aceType, + ace_dacl_type_mapping[i].nfs4_type); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_cached_id_mappings), cmocka_unit_test(test_empty_nfs4_to_dacl), cmocka_unit_test(test_empty_dacl_to_nfs4), + cmocka_unit_test(test_acl_type_nfs4_to_dacl), + cmocka_unit_test(test_acl_type_dacl_to_nfs4), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From c1eb8ec5c3313cebee8dc4ea3643459ced76a2b1 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:28:31 -0700 Subject: [PATCH 036/376] test_nfs4_acls: Add test for flags mapping from NFS4 ACL to DACL Add testcase for the mapping of inheritance flags when mapping from a NFSv4 ACL to a DACL in the security descriptor. The mapping is different between files and directories, as some inheritance flags should never be present for files. Some defined flags like SUCCESSFUL_ACCESS are also not mapped at this point, also verify this behavior. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 16eb61a900c6749c2554d635ce2dd903f5de1704) --- source3/modules/test_nfs4_acls.c | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index b29714d23e3..47ae14d0e65 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -268,6 +268,92 @@ static void test_acl_type_dacl_to_nfs4(void **state) TALLOC_FREE(frame); } +struct ace_flag_mapping_nfs4_to_dacl { + bool is_directory; + uint32_t nfs4_flag; + uint32_t dacl_flag; +} ace_flags_nfs4_to_dacl[] = { + { true, SMB_ACE4_FILE_INHERIT_ACE, + SEC_ACE_FLAG_OBJECT_INHERIT }, + { false, SMB_ACE4_FILE_INHERIT_ACE, + 0 }, + { true, SMB_ACE4_DIRECTORY_INHERIT_ACE, + SEC_ACE_FLAG_CONTAINER_INHERIT }, + { false, SMB_ACE4_DIRECTORY_INHERIT_ACE, + 0 }, + { true, SMB_ACE4_NO_PROPAGATE_INHERIT_ACE, + SEC_ACE_FLAG_NO_PROPAGATE_INHERIT }, + { false, SMB_ACE4_NO_PROPAGATE_INHERIT_ACE, + SEC_ACE_FLAG_NO_PROPAGATE_INHERIT }, + { true, SMB_ACE4_INHERIT_ONLY_ACE, + SEC_ACE_FLAG_INHERIT_ONLY }, + { false, SMB_ACE4_INHERIT_ONLY_ACE, + SEC_ACE_FLAG_INHERIT_ONLY }, + { true, SMB_ACE4_SUCCESSFUL_ACCESS_ACE_FLAG, + 0 }, + { false, SMB_ACE4_SUCCESSFUL_ACCESS_ACE_FLAG, + 0 }, + { true, SMB_ACE4_FAILED_ACCESS_ACE_FLAG, + 0 }, + { false, SMB_ACE4_FAILED_ACCESS_ACE_FLAG, + 0 }, + { true, SMB_ACE4_INHERITED_ACE, + SEC_ACE_FLAG_INHERITED_ACE }, + { false, SMB_ACE4_INHERITED_ACE, + SEC_ACE_FLAG_INHERITED_ACE }, +}; + +static void test_ace_flags_nfs4_to_dacl(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + SMB_ACE4PROP_T nfs4_ace; + int i; + + for (i = 0; i < ARRAY_SIZE(ace_flags_nfs4_to_dacl); i++) { + struct SMB4ACL_T *nfs4_acl; + bool is_directory; + struct security_ace *dacl_aces; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .who.uid = 1000, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = ace_flags_nfs4_to_dacl[i].nfs4_flag, + .aceMask = SMB_ACE4_READ_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + is_directory = ace_flags_nfs4_to_dacl[i].is_directory; + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[2], &sids[3], is_directory, + &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 1); + assert_non_null(dacl_aces); + + assert_int_equal(dacl_aces[0].type, + SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[0].flags, + ace_flags_nfs4_to_dacl[i].dacl_flag); + assert_int_equal(dacl_aces[0].access_mask, SEC_FILE_READ_DATA); + assert_true(dom_sid_equal(&dacl_aces[0].trustee, &sids[0])); + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -276,6 +362,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_empty_dacl_to_nfs4), cmocka_unit_test(test_acl_type_nfs4_to_dacl), cmocka_unit_test(test_acl_type_dacl_to_nfs4), + cmocka_unit_test(test_ace_flags_nfs4_to_dacl), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From ec532e3ed55d94252a23639aad6937118fcf68f1 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:30:12 -0700 Subject: [PATCH 037/376] test_nfs4_acls: Add test for flags mapping from DACL to NFS4 ACL Add testcase for the mapping of inheritance flags from the DACL in the security descriptor to the NFSv4 ACL. The mapping is different for files and directories as some inheritance flags should not be present for files. Also other flags are not mapped at all, verify this behavior. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit bccd2612761e26ee2514935d56927b2c0c000859) --- source3/modules/test_nfs4_acls.c | 87 ++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 47ae14d0e65..a0e7db41b70 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -354,6 +354,92 @@ static void test_ace_flags_nfs4_to_dacl(void **state) TALLOC_FREE(frame); } +struct ace_flag_mapping_dacl_to_nfs4 { + bool is_directory; + uint32_t dacl_flag; + uint32_t nfs4_flag; +} ace_flags_dacl_to_nfs4[] = { + { true, SEC_ACE_FLAG_OBJECT_INHERIT, + SMB_ACE4_FILE_INHERIT_ACE }, + { false, SEC_ACE_FLAG_OBJECT_INHERIT, + 0 }, + { true, SEC_ACE_FLAG_CONTAINER_INHERIT, + SMB_ACE4_DIRECTORY_INHERIT_ACE }, + { false, SEC_ACE_FLAG_CONTAINER_INHERIT, + 0 }, + { true, SEC_ACE_FLAG_NO_PROPAGATE_INHERIT, + SMB_ACE4_NO_PROPAGATE_INHERIT_ACE }, + { false, SEC_ACE_FLAG_NO_PROPAGATE_INHERIT, + 0 }, + { true, SEC_ACE_FLAG_INHERIT_ONLY, + SMB_ACE4_INHERIT_ONLY_ACE }, + { false, SEC_ACE_FLAG_INHERIT_ONLY, + 0 }, + { true, SEC_ACE_FLAG_INHERITED_ACE, + SMB_ACE4_INHERITED_ACE }, + { false, SEC_ACE_FLAG_INHERITED_ACE, + SMB_ACE4_INHERITED_ACE }, + { true, SEC_ACE_FLAG_SUCCESSFUL_ACCESS, + 0 }, + { false, SEC_ACE_FLAG_SUCCESSFUL_ACCESS, + 0 }, + { true, SEC_ACE_FLAG_FAILED_ACCESS, + 0 }, + { false, SEC_ACE_FLAG_FAILED_ACCESS, + 0 }, +}; + +static void test_ace_flags_dacl_to_nfs4(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(ace_flags_dacl_to_nfs4); i++) { + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + bool is_directory; + struct security_ace dacl_aces[1]; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + init_sec_ace(&dacl_aces[0], &sids[0], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + ace_flags_dacl_to_nfs4[i].dacl_flag); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + is_directory = ace_flags_dacl_to_nfs4[i].is_directory; + nfs4_acl = smbacl4_win2nfs4(frame, is_directory, dacl, ¶ms, + 101, 102); + + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 1); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, + ace_flags_dacl_to_nfs4[i].nfs4_flag); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -363,6 +449,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_acl_type_nfs4_to_dacl), cmocka_unit_test(test_acl_type_dacl_to_nfs4), cmocka_unit_test(test_ace_flags_nfs4_to_dacl), + cmocka_unit_test(test_ace_flags_dacl_to_nfs4), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 014ae431e64166de6c97660cfbfc6c90c52b532e Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:33:29 -0700 Subject: [PATCH 038/376] test_nfs4_acls: Add test for mapping permissions from NFS4 ACL to DACL Add testcase for mapping permissions from the NFSv4 ACL to DACL in the security descriptor. The mapping is simple as each permission bit exists on both sides. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 1767027b44a9e4ebd865022e3f8abb0c72bf15c6) --- source3/modules/test_nfs4_acls.c | 77 ++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index a0e7db41b70..42a69453f5a 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -440,6 +440,82 @@ static void test_ace_flags_dacl_to_nfs4(void **state) TALLOC_FREE(frame); } +struct ace_perm_mapping { + uint32_t nfs4_perm; + uint32_t dacl_perm; +} perm_table_nfs4_to_dacl[] = { + { SMB_ACE4_READ_DATA, SEC_FILE_READ_DATA }, + { SMB_ACE4_LIST_DIRECTORY, SEC_DIR_LIST }, + { SMB_ACE4_WRITE_DATA, SEC_FILE_WRITE_DATA }, + { SMB_ACE4_ADD_FILE, SEC_DIR_ADD_FILE }, + { SMB_ACE4_APPEND_DATA, SEC_FILE_APPEND_DATA }, + { SMB_ACE4_ADD_SUBDIRECTORY, SEC_DIR_ADD_SUBDIR, }, + { SMB_ACE4_READ_NAMED_ATTRS, SEC_FILE_READ_EA }, + { SMB_ACE4_READ_NAMED_ATTRS, SEC_DIR_READ_EA }, + { SMB_ACE4_WRITE_NAMED_ATTRS, SEC_FILE_WRITE_EA }, + { SMB_ACE4_WRITE_NAMED_ATTRS, SEC_DIR_WRITE_EA }, + { SMB_ACE4_EXECUTE, SEC_FILE_EXECUTE }, + { SMB_ACE4_EXECUTE, SEC_DIR_TRAVERSE }, + { SMB_ACE4_DELETE_CHILD, SEC_DIR_DELETE_CHILD }, + { SMB_ACE4_READ_ATTRIBUTES, SEC_FILE_READ_ATTRIBUTE }, + { SMB_ACE4_READ_ATTRIBUTES, SEC_DIR_READ_ATTRIBUTE }, + { SMB_ACE4_WRITE_ATTRIBUTES, SEC_FILE_WRITE_ATTRIBUTE }, + { SMB_ACE4_WRITE_ATTRIBUTES, SEC_DIR_WRITE_ATTRIBUTE }, + { SMB_ACE4_DELETE, SEC_STD_DELETE }, + { SMB_ACE4_READ_ACL, SEC_STD_READ_CONTROL }, + { SMB_ACE4_WRITE_ACL, SEC_STD_WRITE_DAC, }, + { SMB_ACE4_WRITE_OWNER, SEC_STD_WRITE_OWNER }, + { SMB_ACE4_SYNCHRONIZE, SEC_STD_SYNCHRONIZE }, +}; + +static void test_nfs4_permissions_to_dacl(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(perm_table_nfs4_to_dacl); i++) { + struct SMB4ACL_T *nfs4_acl; + SMB_ACE4PROP_T nfs4_ace; + struct security_ace *dacl_aces; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .who.uid = 1000, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = perm_table_nfs4_to_dacl[i].nfs4_perm, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[0], &sids[1], false, + &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 1); + assert_non_null(dacl_aces); + + assert_int_equal(dacl_aces[0].type, + SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[0].flags, 0); + assert_int_equal(dacl_aces[0].access_mask, + perm_table_nfs4_to_dacl[i].dacl_perm); + assert_true(dom_sid_equal(&dacl_aces[0].trustee, &sids[0])); + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -450,6 +526,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_acl_type_dacl_to_nfs4), cmocka_unit_test(test_ace_flags_nfs4_to_dacl), cmocka_unit_test(test_ace_flags_dacl_to_nfs4), + cmocka_unit_test(test_nfs4_permissions_to_dacl), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 368c370dc2f82b03da2e910e1116f5afee064c29 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:35:34 -0700 Subject: [PATCH 039/376] test_nfs4_acls: Add test for mapping permissions from DACL to NFS4 ACL Add testcase for mapping the permission flags from the DACL in the Security Descriptor to a NFSv4 ACL. The mapping is straight-forward as the same permission bits exist for Security Descriptors and NFSv4 ACLs. In addition, the code also maps from the generic DACL permissions to a set of NFSv4 permissions, also verify this mapping. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit e4840e680744bd860beedeb5123704c3c0d6a4d7) --- source3/modules/test_nfs4_acls.c | 106 +++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 42a69453f5a..d77eceb1b88 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -516,6 +516,111 @@ static void test_nfs4_permissions_to_dacl(void **state) TALLOC_FREE(frame); } +struct ace_perm_mapping_dacl_to_nfs4 { + uint32_t dacl_perm; + uint32_t nfs4_perm; +} perm_table_dacl_to_nfs4[] = { + { SEC_FILE_READ_DATA, SMB_ACE4_READ_DATA, }, + { SEC_DIR_LIST, SMB_ACE4_LIST_DIRECTORY, }, + { SEC_FILE_WRITE_DATA, SMB_ACE4_WRITE_DATA, }, + { SEC_DIR_ADD_FILE, SMB_ACE4_ADD_FILE, }, + { SEC_FILE_APPEND_DATA, SMB_ACE4_APPEND_DATA, }, + { SEC_DIR_ADD_SUBDIR, SMB_ACE4_ADD_SUBDIRECTORY, }, + { SEC_FILE_READ_EA, SMB_ACE4_READ_NAMED_ATTRS, }, + { SEC_DIR_READ_EA, SMB_ACE4_READ_NAMED_ATTRS, }, + { SEC_FILE_WRITE_EA, SMB_ACE4_WRITE_NAMED_ATTRS, }, + { SEC_DIR_WRITE_EA, SMB_ACE4_WRITE_NAMED_ATTRS, }, + { SEC_FILE_EXECUTE, SMB_ACE4_EXECUTE, }, + { SEC_DIR_TRAVERSE, SMB_ACE4_EXECUTE, }, + { SEC_DIR_DELETE_CHILD, SMB_ACE4_DELETE_CHILD, }, + { SEC_FILE_READ_ATTRIBUTE, SMB_ACE4_READ_ATTRIBUTES, }, + { SEC_DIR_READ_ATTRIBUTE, SMB_ACE4_READ_ATTRIBUTES, }, + { SEC_FILE_WRITE_ATTRIBUTE, SMB_ACE4_WRITE_ATTRIBUTES, }, + { SEC_DIR_WRITE_ATTRIBUTE, SMB_ACE4_WRITE_ATTRIBUTES, }, + { SEC_STD_DELETE, SMB_ACE4_DELETE, }, + { SEC_STD_READ_CONTROL, SMB_ACE4_READ_ACL, }, + { SEC_STD_WRITE_DAC, SMB_ACE4_WRITE_ACL, }, + { SEC_STD_WRITE_OWNER, SMB_ACE4_WRITE_OWNER, }, + { SEC_STD_SYNCHRONIZE, SMB_ACE4_SYNCHRONIZE, }, + { SEC_GENERIC_READ, SMB_ACE4_READ_ACL| + SMB_ACE4_READ_DATA| + SMB_ACE4_READ_ATTRIBUTES| + SMB_ACE4_READ_NAMED_ATTRS| + SMB_ACE4_SYNCHRONIZE }, + { SEC_GENERIC_WRITE, SMB_ACE4_WRITE_ACL| + SMB_ACE4_WRITE_DATA| + SMB_ACE4_WRITE_ATTRIBUTES| + SMB_ACE4_WRITE_NAMED_ATTRS| + SMB_ACE4_SYNCHRONIZE }, + { SEC_GENERIC_EXECUTE, SMB_ACE4_READ_ACL| + SMB_ACE4_READ_ATTRIBUTES| + SMB_ACE4_EXECUTE| + SMB_ACE4_SYNCHRONIZE }, + { SEC_GENERIC_ALL, SMB_ACE4_DELETE| + SMB_ACE4_READ_ACL| + SMB_ACE4_WRITE_ACL| + SMB_ACE4_WRITE_OWNER| + SMB_ACE4_SYNCHRONIZE| + SMB_ACE4_WRITE_ATTRIBUTES| + SMB_ACE4_READ_ATTRIBUTES| + SMB_ACE4_EXECUTE| + SMB_ACE4_READ_NAMED_ATTRS| + SMB_ACE4_WRITE_NAMED_ATTRS| + SMB_ACE4_WRITE_DATA| + SMB_ACE4_APPEND_DATA| + SMB_ACE4_READ_DATA| + SMB_ACE4_DELETE_CHILD }, +}; + +static void test_dacl_permissions_to_nfs4(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(perm_table_nfs4_to_dacl); i++) { + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + struct security_ace dacl_aces[1]; + struct security_acl *dacl; + + init_sec_ace(&dacl_aces[0], &sids[0], + SEC_ACE_TYPE_ACCESS_ALLOWED, + perm_table_dacl_to_nfs4[i].dacl_perm, 0); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, false, dacl, ¶ms, + 101, 102); + + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 1); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, 0); + assert_int_equal(nfs4_ace->aceMask, + perm_table_dacl_to_nfs4[i].nfs4_perm); + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -527,6 +632,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_ace_flags_nfs4_to_dacl), cmocka_unit_test(test_ace_flags_dacl_to_nfs4), cmocka_unit_test(test_nfs4_permissions_to_dacl), + cmocka_unit_test(test_dacl_permissions_to_nfs4), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From dda9e525c55c3602060fffc773e1d31b524ba93f Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:46:23 -0700 Subject: [PATCH 040/376] test_nfs4_acls: Add test for mapping of special NFS4 ACL entries to DACL entries In addition to entries for users and groups, NFSv4 ACLs have the concept of entries for "special" entries. Only the "owner", "group" and "everyone" entries are currently used in the ACL mapping. Add a testcase that verifies the mapping from NFSv4 "special" entries to the DACL in the security descriptor. Verify that only "owner", "group" and "everyone" are mapped and all other "special" entries are ignored. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit f86148948c7f89307a34e31f6ddede6923149d34) --- source3/modules/test_nfs4_acls.c | 139 +++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index d77eceb1b88..5b5b37adc82 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -621,6 +621,144 @@ static void test_dacl_permissions_to_nfs4(void **state) TALLOC_FREE(frame); } +/* + * Create NFS4 ACL with all possible "special" entries. Verify that + * the ones that should be mapped to a DACL are mapped and the other + * ones are ignored. + */ +static void test_special_nfs4_to_dacl(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + struct SMB4ACL_T *nfs4_acl; + SMB_ACE4PROP_T nfs4_ace; + struct security_ace *dacl_aces; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_OWNER, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_READ_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_GROUP, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_WRITE_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_EVERYONE, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_APPEND_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_INTERACTIVE, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_READ_NAMED_ATTRS, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_NETWORK, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_WRITE_NAMED_ATTRS, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_DIALUP, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_EXECUTE, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_BATCH, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_READ_ATTRIBUTES, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_ANONYMOUS, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_WRITE_ATTRIBUTES, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_AUTHENTICATED, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_READ_ACL, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_SERVICE, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = SMB_ACE4_WRITE_ACL, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[0], &sids[1], false, + &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 3); + assert_non_null(dacl_aces); + + assert_int_equal(dacl_aces[0].type, SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[0].flags, 0); + assert_int_equal(dacl_aces[0].access_mask, SEC_FILE_READ_DATA); + assert_true(dom_sid_equal(&dacl_aces[0].trustee, &sids[0])); + + assert_int_equal(dacl_aces[1].type, SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[1].flags, 0); + assert_int_equal(dacl_aces[1].access_mask, SEC_FILE_WRITE_DATA); + assert_true(dom_sid_equal(&dacl_aces[1].trustee, &sids[1])); + + assert_int_equal(dacl_aces[2].type, SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[2].flags, 0); + assert_int_equal(dacl_aces[2].access_mask, SEC_FILE_APPEND_DATA); + assert_true(dom_sid_equal(&dacl_aces[2].trustee, &global_sid_World)); + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -633,6 +771,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_ace_flags_dacl_to_nfs4), cmocka_unit_test(test_nfs4_permissions_to_dacl), cmocka_unit_test(test_dacl_permissions_to_nfs4), + cmocka_unit_test(test_special_nfs4_to_dacl), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From aa466a0104d95f0a512c5d740df1c17a06116bd4 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:53:15 -0700 Subject: [PATCH 041/376] test_nfs4_acls: Add test for mapping from DACL to special NFS4 ACL entries Add testcase for mapping from entries in the DACL security descriptor to "special" entries in the NFSv4 ACL. Verify that the WORLD well-known SID maps to "everyone" in the NFSv4 ACL. Verify that the "Unix NFS" SID is ignored, as there is no meaningful mapping for this entry. Verify that SID entries matching the owner or group are mapped to "special owner" or "special group", but only if no inheritance flags are used. "special owner" and "special group" with inheritance flags have the meaning of CREATOR OWNER and CREATOR GROUP and will be tested in another testcase. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 1f1fa5bde2c76636c1beec39c21067b252ea10be) --- source3/modules/test_nfs4_acls.c | 108 +++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 5b5b37adc82..46119f83dc4 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -759,6 +759,113 @@ static void test_special_nfs4_to_dacl(void **state) TALLOC_FREE(frame); } +static void test_dacl_to_special_nfs4(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + struct security_ace dacl_aces[6]; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_dontcare, + .map_full_control = true, + }; + + /* + * global_Sid_World is mapped to EVERYONE. + */ + init_sec_ace(&dacl_aces[0], &global_sid_World, + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_WRITE_DATA, 0); + /* + * global_sid_Unix_NFS is ignored. + */ + init_sec_ace(&dacl_aces[1], &global_sid_Unix_NFS, + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, 0); + /* + * Anything that maps to owner or owning group with inheritance flags + * is NOT mapped to special owner or special group. + */ + init_sec_ace(&dacl_aces[2], &sids[0], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT); + init_sec_ace(&dacl_aces[3], &sids[0], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); + init_sec_ace(&dacl_aces[4], &sids[1], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT); + init_sec_ace(&dacl_aces[5], &sids[1], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, true, dacl, ¶ms, 1000, 1001); + + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 5); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, SMB_ACE4_ID_SPECIAL); + assert_int_equal(nfs4_ace->who.special_id, SMB_ACE4_WHO_EVERYONE); + assert_int_equal(nfs4_ace->aceFlags, 0); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_WRITE_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_IDENTIFIER_GROUP| + SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->who.gid, 1001); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_IDENTIFIER_GROUP| + SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE); + assert_int_equal(nfs4_ace->who.gid, 1001); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + assert_null(smb_next_ace4(nfs4_ace_container)); + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -772,6 +879,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_nfs4_permissions_to_dacl), cmocka_unit_test(test_dacl_permissions_to_nfs4), cmocka_unit_test(test_special_nfs4_to_dacl), + cmocka_unit_test(test_dacl_to_special_nfs4), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 4e46dbc7749753b9d6d89ef9aa995cb49e53969a Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:55:59 -0700 Subject: [PATCH 042/376] test_nfs4_acls: Add test for mapping CREATOR entries to NFS4 ACL entries Add testcase for mapping DACL entries CREATOR OWNER and CREATOR GROUP with inheritance flag in the security descriptor to NFSv4 "special owner" and "special group" entries. This is the correct mapping for these entries as inheriting "special owner" and "special group" grants permissions to the actual owner and owning group of the new file or directory, similar to what CREATOR entries do. The other side is that CREATOR entries without any inheritance flags do not make sense, so these are not mapped to NFSv4 ACL entries. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit bfcc19b705f83bdd5cf665fd4daf43e7eae997a9) --- source3/modules/test_nfs4_acls.c | 108 +++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 46119f83dc4..dcdcb89823f 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -866,6 +866,113 @@ static void test_dacl_to_special_nfs4(void **state) TALLOC_FREE(frame); } +struct creator_ace_flags { + uint32_t dacl_flags; + uint32_t nfs4_flags; +} creator_ace_flags[] = { + { 0, 0 }, + + { SEC_ACE_FLAG_INHERIT_ONLY, 0 }, + + { SEC_ACE_FLAG_CONTAINER_INHERIT, SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE }, + + { SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY, SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE }, + + { SEC_ACE_FLAG_OBJECT_INHERIT, SMB_ACE4_FILE_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE }, + { SEC_ACE_FLAG_OBJECT_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY, SMB_ACE4_FILE_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE }, + + { SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_OBJECT_INHERIT, SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_FILE_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE }, + + { SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_OBJECT_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY, SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_FILE_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE }, +}; + +static void test_dacl_creator_to_nfs4(void **state) +{ + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(creator_ace_flags); i++) { + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + struct security_ace dacl_aces[2]; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + init_sec_ace(&dacl_aces[0], &global_sid_Creator_Owner, + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + creator_ace_flags[i].dacl_flags); + init_sec_ace(&dacl_aces[1], &global_sid_Creator_Group, + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + creator_ace_flags[i].dacl_flags); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, true, dacl, ¶ms, + 101, 102); + + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + + if (creator_ace_flags[i].nfs4_flags == 0) { + /* + * CREATOR OWNER and CREATOR GROUP not mapped + * in thise case. + */ + assert_null(smb_first_ace4(nfs4_acl)); + } else { + assert_int_equal(smb_get_naces(nfs4_acl), 2); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace); + assert_int_equal(nfs4_ace->flags, SMB_ACE4_ID_SPECIAL); + assert_int_equal(nfs4_ace->who.special_id, + SMB_ACE4_WHO_OWNER); + assert_int_equal(nfs4_ace->aceFlags, + creator_ace_flags[i].nfs4_flags); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace); + assert_int_equal(nfs4_ace->flags, SMB_ACE4_ID_SPECIAL); + assert_int_equal(nfs4_ace->who.special_id, + SMB_ACE4_WHO_GROUP); + assert_int_equal(nfs4_ace->aceFlags, + creator_ace_flags[i].nfs4_flags); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + } + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -880,6 +987,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_dacl_permissions_to_nfs4), cmocka_unit_test(test_special_nfs4_to_dacl), cmocka_unit_test(test_dacl_to_special_nfs4), + cmocka_unit_test(test_dacl_creator_to_nfs4), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 61002278b801a1d5814954c44371e73d0a2eee43 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 11:57:45 -0700 Subject: [PATCH 043/376] test_nfs4_acls: Add test for mapping from NFS4 to DACL CREATOR entries Add testcase for mapping from NFSv4 ACL entries for "special owner" and "special group" to DACL entries in the security descriptor. Each NFSv4 entry here with INHERIT_ONLY maps directly to a CREATOR OWNER or CREATOR GROUP entry in the DACL. Entries without INHERIT_ONLY map to the CREATOR entry and an additional explicit entry granting permission on the current object. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 3c9cda0f6d80258ef0c2a80d6e24dfb650fea1b1) --- source3/modules/test_nfs4_acls.c | 122 +++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index dcdcb89823f..e4e5f1f8b6e 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -973,6 +973,127 @@ static void test_dacl_creator_to_nfs4(void **state) TALLOC_FREE(frame); } +struct creator_owner_nfs4_to_dacl { + uint32_t special_id; + uint32_t nfs4_ace_flags; + uint32_t dacl_ace_flags; +} creator_owner_nfs4_to_dacl[] = { + { SMB_ACE4_WHO_OWNER, + SMB_ACE4_FILE_INHERIT_ACE, + SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY }, + { SMB_ACE4_WHO_OWNER, + SMB_ACE4_DIRECTORY_INHERIT_ACE, + SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY }, + { SMB_ACE4_WHO_OWNER, + SMB_ACE4_FILE_INHERIT_ACE|SMB_ACE4_DIRECTORY_INHERIT_ACE, + SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY }, + { SMB_ACE4_WHO_GROUP, + SMB_ACE4_FILE_INHERIT_ACE, + SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY }, + { SMB_ACE4_WHO_GROUP, + SMB_ACE4_DIRECTORY_INHERIT_ACE, + SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY }, + { SMB_ACE4_WHO_GROUP, + SMB_ACE4_FILE_INHERIT_ACE|SMB_ACE4_DIRECTORY_INHERIT_ACE, + SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT| + SEC_ACE_FLAG_INHERIT_ONLY }, +}; + +static void test_nfs4_to_dacl_creator(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(creator_owner_nfs4_to_dacl); i++) { + struct SMB4ACL_T *nfs4_acl; + SMB_ACE4PROP_T nfs4_ace; + struct security_ace *dacl_aces, *creator_dacl_ace; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id + = creator_owner_nfs4_to_dacl[i].special_id, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags + = creator_owner_nfs4_to_dacl[i].nfs4_ace_flags, + .aceMask = SMB_ACE4_READ_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[0], &sids[1], true, + &dacl_aces, &good_aces)); + assert_non_null(dacl_aces); + + if (creator_owner_nfs4_to_dacl[i].nfs4_ace_flags & + SMB_ACE4_INHERIT_ONLY_ACE) { + /* + * Only one ACE entry for the CREATOR ACE entry. + */ + assert_int_equal(good_aces, 1); + creator_dacl_ace = &dacl_aces[0]; + } else { + /* + * This creates an additional ACE entry for + * the permissions on the current object. + */ + assert_int_equal(good_aces, 2); + + assert_int_equal(dacl_aces[0].type, + SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[0].flags, 0); + assert_int_equal(dacl_aces[0].access_mask, + SEC_FILE_READ_DATA); + + if (creator_owner_nfs4_to_dacl[i].special_id == + SMB_ACE4_WHO_OWNER) { + assert_true(dom_sid_equal(&dacl_aces[0].trustee, + &sids[0])); + } + + if (creator_owner_nfs4_to_dacl[i].special_id == + SMB_ACE4_WHO_GROUP) { + assert_true(dom_sid_equal(&dacl_aces[0].trustee, + &sids[1])); + } + + creator_dacl_ace = &dacl_aces[1]; + } + + assert_int_equal(creator_dacl_ace->type, + SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(creator_dacl_ace->flags, + creator_owner_nfs4_to_dacl[i].dacl_ace_flags); + assert_int_equal(creator_dacl_ace->access_mask, + SEC_FILE_READ_DATA); + if (creator_owner_nfs4_to_dacl[i].special_id == + SMB_ACE4_WHO_OWNER) { + assert_true(dom_sid_equal(&creator_dacl_ace->trustee, + &global_sid_Creator_Owner)); + } + + if (creator_owner_nfs4_to_dacl[i].special_id == + SMB_ACE4_WHO_GROUP) { + assert_true(dom_sid_equal(&creator_dacl_ace->trustee, + &global_sid_Creator_Group)); + } + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -988,6 +1109,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_special_nfs4_to_dacl), cmocka_unit_test(test_dacl_to_special_nfs4), cmocka_unit_test(test_dacl_creator_to_nfs4), + cmocka_unit_test(test_nfs4_to_dacl_creator), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 31d60e8cf2c27e7c05f18b087db5c5aa48075b79 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 12:02:58 -0700 Subject: [PATCH 044/376] test_nfs4_acls: Add test for 'map full control' option "map full control" when enabled adds the DELETE_CHILD permission, when all other permissions are present. This allows Windows clients to display the "FULL CONTROL" permissions. Add a testcase that verifies this mapping when mapping from NFSv4 ACL to the DACL in the security descriptor. Also verify that switching the option off disables this behavior. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 30677df4dac4ebfcf4e3198db33f14be37948197) --- source3/modules/test_nfs4_acls.c | 82 ++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index e4e5f1f8b6e..733217b1f2e 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1094,6 +1094,87 @@ static void test_nfs4_to_dacl_creator(void **state) TALLOC_FREE(frame); } +struct nfs4_to_dacl_map_full_control{ + bool is_dir; + bool config; + bool delete_child_added; +} nfs4_to_dacl_full_control[] = { + { true, true, false }, + { true, false, false }, + { false, true, true }, + { false, false, false }, +}; + +static void test_full_control_nfs4_to_dacl(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(nfs4_to_dacl_full_control); i++) { + struct SMB4ACL_T *nfs4_acl; + SMB_ACE4PROP_T nfs4_ace; + struct security_ace *dacl_aces; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = nfs4_to_dacl_full_control[i].config, + }; + const uint32_t nfs4_ace_mask_except_deletes = + SMB_ACE4_READ_DATA|SMB_ACE4_WRITE_DATA| + SMB_ACE4_APPEND_DATA|SMB_ACE4_READ_NAMED_ATTRS| + SMB_ACE4_WRITE_NAMED_ATTRS|SMB_ACE4_EXECUTE| + SMB_ACE4_READ_ATTRIBUTES|SMB_ACE4_WRITE_ATTRIBUTES| + SMB_ACE4_READ_ACL|SMB_ACE4_WRITE_ACL| + SMB_ACE4_WRITE_OWNER|SMB_ACE4_SYNCHRONIZE; + const uint32_t dacl_ace_mask_except_deletes = + SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA| + SEC_FILE_APPEND_DATA|SEC_FILE_READ_EA| + SEC_FILE_WRITE_EA|SEC_FILE_EXECUTE| + SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE| + SEC_STD_READ_CONTROL|SEC_STD_WRITE_DAC| + SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .who.uid = 1000, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = 0, + .aceMask = nfs4_ace_mask_except_deletes, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + assert_true( + smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[0], &sids[1], + nfs4_to_dacl_full_control[i].is_dir, + &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 1); + assert_non_null(dacl_aces); + + assert_int_equal(dacl_aces[0].type, + SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[0].flags, 0); + assert_true(dom_sid_equal(&dacl_aces[0].trustee, &sids[0])); + if (nfs4_to_dacl_full_control[i].delete_child_added) { + assert_int_equal(dacl_aces[0].access_mask, + dacl_ace_mask_except_deletes| + SEC_DIR_DELETE_CHILD); + } else { + assert_int_equal(dacl_aces[0].access_mask, + dacl_ace_mask_except_deletes); + } + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -1110,6 +1191,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_dacl_to_special_nfs4), cmocka_unit_test(test_dacl_creator_to_nfs4), cmocka_unit_test(test_nfs4_to_dacl_creator), + cmocka_unit_test(test_full_control_nfs4_to_dacl), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 490d13557a4c2bd7046c85080930c0fc9d0d7ee0 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 12:07:36 -0700 Subject: [PATCH 045/376] test_nfs4_acls: Add test for acedup settings The NFSv4 ACL mapping code has a setting nfs4:acedup. Depending on the setting, when mapping from DACLs to NFSv4 ACLs, duplicate ACL entries are either merged, ignored or rejected. Add a testcase that has duplicate ACL entries and verify the expected behavior for all possible settings of the nfs4:acedup option. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 9671bf2b9f055012057620207624aa2f4ea6833e) --- source3/modules/test_nfs4_acls.c | 124 +++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 733217b1f2e..c4f3d8052e4 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1175,6 +1175,129 @@ static void test_full_control_nfs4_to_dacl(void **state) TALLOC_FREE(frame); } +struct acedup_settings { + enum smbacl4_acedup_enum setting; +} acedup_settings[] = { + { e_dontcare }, + { e_reject }, + { e_ignore }, + { e_merge }, +}; + +static void test_dacl_to_nfs4_acedup_settings(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(acedup_settings); i++) { + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + struct security_ace dacl_aces[2]; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = acedup_settings[i].setting, + .map_full_control = true, + }; + + init_sec_ace(&dacl_aces[0], &sids[0], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT); + init_sec_ace(&dacl_aces[1], &sids[0], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_WRITE_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, true, dacl, ¶ms, + 101, 102); + + switch(params.acedup) { + case e_dontcare: + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 2); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, + SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, + SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->aceMask, + SMB_ACE4_WRITE_DATA); + break; + + case e_reject: + assert_null(nfs4_acl); + assert_int_equal(errno, EINVAL); + break; + + case e_ignore: + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 1); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, + SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + break; + + case e_merge: + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 1); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, + SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->aceMask, + SMB_ACE4_READ_DATA| + SMB_ACE4_WRITE_DATA); + break; + + default: + fail_msg("Unexpected value for acedup: %d\n", + params.acedup); + }; + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -1192,6 +1315,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_dacl_creator_to_nfs4), cmocka_unit_test(test_nfs4_to_dacl_creator), cmocka_unit_test(test_full_control_nfs4_to_dacl), + cmocka_unit_test(test_dacl_to_nfs4_acedup_settings), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 4022997f0305ff39db9af2ecb24bd1a2aa9ee0a6 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 12:09:04 -0700 Subject: [PATCH 046/376] test_nfs4_acls: Add test for matching DACL entries for acedup The NFSv4 mapping code has a config option nfs4:acedup for the mapping path from DACLs to NFSv4 ACLs. Part of this codepath is detecting duplicate ACL entries. Add a testcase with different ACL entries and verify that only exactly matching entries are detected as duplicates and treated accordingly. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit f55cdf42a14f314102f2e13cb06d4db48c08ad4b) --- source3/modules/test_nfs4_acls.c | 122 +++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index c4f3d8052e4..80078311ce8 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1298,6 +1298,127 @@ static void test_dacl_to_nfs4_acedup_settings(void **state) TALLOC_FREE(frame); } +struct acedup_match { + int sid_idx1; + enum security_ace_type type1; + uint32_t ace_mask1; + uint8_t flag1; + int sid_idx2; + enum security_ace_type type2; + uint32_t ace_mask2; + uint8_t flag2; + bool match; +} acedup_match[] = { + { 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + true }, + { 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + 1, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + false }, + { 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + 0, SEC_ACE_TYPE_ACCESS_DENIED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + false }, + { 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_WRITE_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + true }, + { 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_CONTAINER_INHERIT, + false }, + { 0, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + 5, SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT, + false }, +}; + +static void test_dacl_to_nfs4_acedup_match(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + for (i = 0; i < ARRAY_SIZE(acedup_match); i++) { + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + struct security_ace dacl_aces[2]; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_ignore, + .map_full_control = true, + }; + + init_sec_ace(&dacl_aces[0], + &sids[acedup_match[i].sid_idx1], + acedup_match[i].type1, + acedup_match[i].ace_mask1, + acedup_match[i].flag1); + init_sec_ace(&dacl_aces[1], + &sids[acedup_match[i].sid_idx2], + acedup_match[i].type2, + acedup_match[i].ace_mask2, + acedup_match[i].flag2); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, true, dacl, ¶ms, + 101, 102); + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + + if (acedup_match[i].match) { + assert_int_equal(smb_get_naces(nfs4_acl), 1); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, + SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + } else { + assert_int_equal(smb_get_naces(nfs4_acl), 2); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->who.uid, 1000); + assert_int_equal(nfs4_ace->aceFlags, + SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + } + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -1316,6 +1437,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_nfs4_to_dacl_creator), cmocka_unit_test(test_full_control_nfs4_to_dacl), cmocka_unit_test(test_dacl_to_nfs4_acedup_settings), + cmocka_unit_test(test_dacl_to_nfs4_acedup_match), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From d3a9648eb63a0624ba2c500ab0a1c477140912ec Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 12:16:08 -0700 Subject: [PATCH 047/376] test_nfs4_acls: Add test for mapping from DACL to NFS4 ACL with config special The mapping code between NFSv4 ACLs and security descriptors still has the deprecated config setting "nfs4:mode = special". This should not be used as it has security problems: All entries matching owner or group are mapped to "special owner" or "special group", which can change its meaning when being inherited to a new file or directory with different owner and owning group. This mode should eventually be removed, but as long as it still exists add testcases to verify the expected behavior. This patch adds the testcase for "nfs4:mode = special" when mapping from the DACL in the security descriptor to the NFSv4 ACL. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 7ae06d96eb59722154d30e21949f9dba4f2f0bc6) --- source3/modules/test_nfs4_acls.c | 119 +++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 80078311ce8..eda2fe56d32 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1419,6 +1419,124 @@ static void test_dacl_to_nfs4_acedup_match(void **state) TALLOC_FREE(frame); } +static void test_dacl_to_nfs4_config_special(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + struct security_ace dacl_aces[6]; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_special, + .do_chown = true, + .acedup = e_dontcare, + .map_full_control = true, + }; + + /* + * global_sid_Creator_Owner or global_sid_Special_Group is NOT mapped + * to SMB_ACE4_ID_SPECIAL. + */ + init_sec_ace(&dacl_aces[0], &global_sid_Creator_Owner, + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT); + init_sec_ace(&dacl_aces[1], &global_sid_Creator_Group, + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_WRITE_DATA, + SEC_ACE_FLAG_CONTAINER_INHERIT); + /* + * Anything that maps to owner or owning group with inheritance flags + * IS mapped to special owner or special group. + */ + init_sec_ace(&dacl_aces[2], &sids[0], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT); + init_sec_ace(&dacl_aces[3], &sids[0], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); + init_sec_ace(&dacl_aces[4], &sids[1], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_OBJECT_INHERIT); + init_sec_ace(&dacl_aces[5], &sids[1], + SEC_ACE_TYPE_ACCESS_ALLOWED, SEC_FILE_READ_DATA, + SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, true, dacl, ¶ms, 1000, 1001); + + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 6); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->who.uid, 1003); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, 0); + assert_int_equal(nfs4_ace->aceFlags, + SMB_ACE4_IDENTIFIER_GROUP| + SMB_ACE4_DIRECTORY_INHERIT_ACE); + assert_int_equal(nfs4_ace->who.gid, 1004); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_WRITE_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, SMB_ACE4_ID_SPECIAL); + assert_int_equal(nfs4_ace->who.special_id, SMB_ACE4_WHO_OWNER); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, SMB_ACE4_ID_SPECIAL); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE); + assert_int_equal(nfs4_ace->who.special_id, SMB_ACE4_WHO_OWNER); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, SMB_ACE4_ID_SPECIAL); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_IDENTIFIER_GROUP| + SMB_ACE4_FILE_INHERIT_ACE); + assert_int_equal(nfs4_ace->who.special_id, SMB_ACE4_WHO_GROUP); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, SMB_ACE4_ID_SPECIAL); + assert_int_equal(nfs4_ace->aceFlags, SMB_ACE4_IDENTIFIER_GROUP| + SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE); + assert_int_equal(nfs4_ace->who.special_id, SMB_ACE4_WHO_GROUP); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + assert_null(smb_next_ace4(nfs4_ace_container)); + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -1438,6 +1556,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_full_control_nfs4_to_dacl), cmocka_unit_test(test_dacl_to_nfs4_acedup_settings), cmocka_unit_test(test_dacl_to_nfs4_acedup_match), + cmocka_unit_test(test_dacl_to_nfs4_config_special), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 2de4919e8a33334cf7c10b9aa407f4c7cff4e53d Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 12:23:02 -0700 Subject: [PATCH 048/376] test_nfs4_acls: Add test for mapping from NFS4 to DACL in config mode special The mapping code between NFSv4 ACLs and security descriptors still has the deprecated config setting "nfs4:mode = special". This should not be used as it has security problems: All entries matching owner or group are mapped to "special owner" or "special group", which can change its meaning when being inherited to a new file or directory with different owner and owning group. This mode should eventually be removed, but as long as it still exists add testcases to verify the expected behavior. This patch adds the testcase for "nfs4:mode = special" when mapping from the NFS4 ACL to the DACL in the security descriptor. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 829c5ea99685c0629fd67ed0528897534ff35b36) --- source3/modules/test_nfs4_acls.c | 63 ++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index eda2fe56d32..341bf179ea9 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1537,6 +1537,68 @@ static void test_dacl_to_nfs4_config_special(void **state) TALLOC_FREE(frame); } +static void test_nfs4_to_dacl_config_special(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + struct SMB4ACL_T *nfs4_acl; + SMB_ACE4PROP_T nfs4_ace; + struct security_ace *dacl_aces; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_special, + .do_chown = true, + .acedup = e_dontcare, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + /* + * In config mode special, this is not mapped to Creator Owner + */ + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_OWNER, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = SMB_ACE4_FILE_INHERIT_ACE, + .aceMask = SMB_ACE4_READ_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + /* + * In config mode special, this is not mapped to Creator Group + */ + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = SMB_ACE4_ID_SPECIAL, + .who.special_id = SMB_ACE4_WHO_GROUP, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = SMB_ACE4_DIRECTORY_INHERIT_ACE, + .aceMask = SMB_ACE4_WRITE_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[0], &sids[1], true, + &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 2); + assert_non_null(dacl_aces); + + assert_int_equal(dacl_aces[0].type, SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[0].flags, SEC_ACE_FLAG_OBJECT_INHERIT); + assert_int_equal(dacl_aces[0].access_mask, SEC_FILE_READ_DATA); + assert_true(dom_sid_equal(&dacl_aces[0].trustee, &sids[0])); + + assert_int_equal(dacl_aces[1].type, SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[1].flags, SEC_ACE_FLAG_CONTAINER_INHERIT); + assert_int_equal(dacl_aces[1].access_mask, SEC_FILE_WRITE_DATA); + assert_true(dom_sid_equal(&dacl_aces[1].trustee, &sids[1])); + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -1557,6 +1619,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_dacl_to_nfs4_acedup_settings), cmocka_unit_test(test_dacl_to_nfs4_acedup_match), cmocka_unit_test(test_dacl_to_nfs4_config_special), + cmocka_unit_test(test_nfs4_to_dacl_config_special), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 7d73c37ae7bbc102dab469f5709b1a54de7a0a74 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 12:50:42 -0700 Subject: [PATCH 049/376] test_nfs4_acls: Add test for mapping from NFS4 ACL to DACL with IDMAP_TYPE_BOTH When id mappings use IDMAP_TYPE_BOTH, the NFSv4 ACL mapping code is not aware whether a particular entry is for a user or a group. The underlying assumption then is that is should not matter, as both the ACL mapping maps everything to NFSv4 ACL group entries and the user's token will contain gid entries for the groups. Add a testcase to verify that when mapping from NFSv4 ACL entries to DACLs with IDMAP_TYPE_BOTH, all entries are mapped as expected. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 86480410aec1d2331c65826a13f909492165a291) --- source3/modules/test_nfs4_acls.c | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 341bf179ea9..964af4ff057 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1599,6 +1599,72 @@ static void test_nfs4_to_dacl_config_special(void **state) TALLOC_FREE(frame); } +struct nfs_to_dacl_idmap_both { + uint32_t nfs4_flags; + uint32_t nfs4_id; + struct dom_sid *sid; +}; + +static void test_nfs4_to_dacl_idmap_type_both(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + struct nfs_to_dacl_idmap_both nfs_to_dacl_idmap_both[] = { + { 0, 1002, &sids[2] }, + { SMB_ACE4_IDENTIFIER_GROUP, 1002, &sids[2] }, + { 0, 1005, &sids[6] }, + { SMB_ACE4_IDENTIFIER_GROUP, 1005, &sids[6] }, + }; + + for (i = 0; i < ARRAY_SIZE(nfs_to_dacl_idmap_both); i++) { + struct SMB4ACL_T *nfs4_acl; + struct security_ace *dacl_aces; + SMB_ACE4PROP_T nfs4_ace; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = nfs_to_dacl_idmap_both[i].nfs4_flags, + .aceMask = SMB_ACE4_READ_DATA, + }; + + if (nfs_to_dacl_idmap_both[i].nfs4_flags & + SMB_ACE4_IDENTIFIER_GROUP) { + nfs4_ace.who.gid = nfs_to_dacl_idmap_both[i].nfs4_id; + } else { + nfs4_ace.who.uid = nfs_to_dacl_idmap_both[i].nfs4_id; + } + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[2], &sids[2], + false, &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 1); + assert_non_null(dacl_aces); + + assert_int_equal(dacl_aces[0].type, + SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[0].flags, 0); + assert_int_equal(dacl_aces[0].access_mask, SEC_FILE_READ_DATA); + assert_true(dom_sid_equal(&dacl_aces[0].trustee, + nfs_to_dacl_idmap_both[i].sid)); + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -1620,6 +1686,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_dacl_to_nfs4_acedup_match), cmocka_unit_test(test_dacl_to_nfs4_config_special), cmocka_unit_test(test_nfs4_to_dacl_config_special), + cmocka_unit_test(test_nfs4_to_dacl_idmap_type_both), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 0313f1552f9665ed485aa2c7224f491be8511eff Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 13:04:44 -0700 Subject: [PATCH 050/376] test_nfs4_acls: Add test for mapping from DACL to NFS4 ACL with IDMAP_TYPE_BOTH When id mappings use IDMAP_TYPE_BOTH, the NFSv4 ACL mapping code is not aware whether a particular entry is for a user or a group. The underlying assumption then is that is should not matter, as both the ACL mapping maps everything to NFSv4 ACL group entries and the user's token will contain gid entries for the groups. Add a testcase to verify that when mapping from DACLS to NFSv4 ACL entries with IDMAP_TYPE_BOTH, all entries are mapped as expected. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 38331b00521ef764893a74add01758f14567d901) --- source3/modules/test_nfs4_acls.c | 85 ++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 964af4ff057..d7152a0737a 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1665,6 +1665,90 @@ static void test_nfs4_to_dacl_idmap_type_both(void **state) TALLOC_FREE(frame); } +struct dacl_to_nfs4_idmap_both { + struct dom_sid *sid; + uint32_t dacl_flags; + uint32_t nfs4_flags; + uint32_t nfs4_ace_flags; + uint32_t nfs4_id; +}; + +/* + * IDMAP_TYPE_BOTH always creates group entries. + */ +static void test_dacl_to_nfs4_idmap_type_both(void **state) +{ + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + int i; + + struct dacl_to_nfs4_idmap_both dacl_to_nfs4_idmap_both[] = { + { &sids[2], 0, + SMB_ACE4_ID_SPECIAL, SMB_ACE4_IDENTIFIER_GROUP, SMB_ACE4_WHO_GROUP }, + { &sids[2], SEC_ACE_FLAG_OBJECT_INHERIT, + 0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1002 }, + { &sids[6], 0, + 0, SMB_ACE4_IDENTIFIER_GROUP, 1005 }, + { &sids[6], SEC_ACE_FLAG_OBJECT_INHERIT, + 0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1005 }, + }; + + for (i = 0; i < ARRAY_SIZE(dacl_to_nfs4_idmap_both); i++) { + struct SMB4ACL_T *nfs4_acl; + struct SMB4ACE_T *nfs4_ace_container; + SMB_ACE4PROP_T *nfs4_ace; + struct security_ace dacl_aces[1]; + struct security_acl *dacl; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_merge, + .map_full_control = true, + }; + + init_sec_ace(&dacl_aces[0], dacl_to_nfs4_idmap_both[i].sid, + SEC_ACE_TYPE_ACCESS_ALLOWED, + SEC_FILE_READ_DATA, + dacl_to_nfs4_idmap_both[i].dacl_flags); + dacl = make_sec_acl(frame, SECURITY_ACL_REVISION_ADS, + ARRAY_SIZE(dacl_aces), dacl_aces); + assert_non_null(dacl); + + nfs4_acl = smbacl4_win2nfs4(frame, true, dacl, ¶ms, + 1002, 1002); + + assert_non_null(nfs4_acl); + assert_int_equal(smbacl4_get_controlflags(nfs4_acl), + SEC_DESC_SELF_RELATIVE); + assert_int_equal(smb_get_naces(nfs4_acl), 1); + + nfs4_ace_container = smb_first_ace4(nfs4_acl); + assert_non_null(nfs4_ace_container); + assert_null(smb_next_ace4(nfs4_ace_container)); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, + dacl_to_nfs4_idmap_both[i].nfs4_flags); + assert_int_equal(nfs4_ace->aceFlags, + dacl_to_nfs4_idmap_both[i].nfs4_ace_flags); + if (nfs4_ace->flags & SMB_ACE4_ID_SPECIAL) { + assert_int_equal(nfs4_ace->who.special_id, + dacl_to_nfs4_idmap_both[i].nfs4_id); + } else if (nfs4_ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) { + assert_int_equal(nfs4_ace->who.gid, + dacl_to_nfs4_idmap_both[i].nfs4_id); + } else { + assert_int_equal(nfs4_ace->who.uid, + dacl_to_nfs4_idmap_both[i].nfs4_id); + } + assert_int_equal(nfs4_ace->aceType, + SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + } + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -1687,6 +1771,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_dacl_to_nfs4_config_special), cmocka_unit_test(test_nfs4_to_dacl_config_special), cmocka_unit_test(test_nfs4_to_dacl_idmap_type_both), + cmocka_unit_test(test_dacl_to_nfs4_idmap_type_both), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From 6d88ab39e8ed469a9279870d88b28c568ce3a687 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 26 Jun 2019 13:24:16 -0700 Subject: [PATCH 051/376] nfs4_acls: Use sids_to_unixids to lookup uid or gid This is the newer API to lookup id mappings and will make it easier to add to the IDMAP_TYPE_BOTH case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit d9a2ff559e1ad953141b1118a9e370496f1f61fa) --- source3/modules/nfs4_acls.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 5543b3a7f58..4069c9310ed 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -21,6 +21,7 @@ #include "smbd/smbd.h" #include "nfs4_acls.h" #include "librpc/gen_ndr/ndr_security.h" +#include "librpc/gen_ndr/idmap.h" #include "../libcli/security/dom_sid.h" #include "../libcli/security/security.h" #include "dbwrap/dbwrap.h" @@ -719,14 +720,21 @@ static bool smbacl4_fill_ace4( return false; } } else { - uid_t uid; - gid_t gid; + struct unixid unixid; + bool ok; - if (sid_to_gid(&ace_nt->trustee, &gid)) { + ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid); + if (!ok) { + DBG_WARNING("Could not convert %s to uid or gid.\n", + dom_sid_str_buf(&ace_nt->trustee, &buf)); + return false; + } + + if (unixid.type == ID_TYPE_GID || unixid.type == ID_TYPE_BOTH) { ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; - ace_v4->who.gid = gid; - } else if (sid_to_uid(&ace_nt->trustee, &uid)) { - ace_v4->who.uid = uid; + ace_v4->who.gid = unixid.id; + } else if (unixid.type == ID_TYPE_UID) { + ace_v4->who.uid = unixid.id; } else if (dom_sid_compare_domain(&ace_nt->trustee, &global_sid_Unix_NFS) == 0) { return false; -- 2.17.1 From b1b8e37881f5583f5b7770c46a8db4162e614884 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 15 Jul 2019 13:15:32 -0700 Subject: [PATCH 052/376] nfs4_acls: Use switch/case for checking idmap type BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit f198a0867e71f248d4887ab0b6f2832123b16d11) --- source3/modules/nfs4_acls.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 4069c9310ed..f8861e9058b 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -730,18 +730,27 @@ static bool smbacl4_fill_ace4( return false; } - if (unixid.type == ID_TYPE_GID || unixid.type == ID_TYPE_BOTH) { + if (dom_sid_compare_domain(&ace_nt->trustee, + &global_sid_Unix_NFS) == 0) { + return false; + } + + switch (unixid.type) { + case ID_TYPE_BOTH: ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; ace_v4->who.gid = unixid.id; - } else if (unixid.type == ID_TYPE_UID) { + break; + case ID_TYPE_GID: + ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; + ace_v4->who.gid = unixid.id; + break; + case ID_TYPE_UID: ace_v4->who.uid = unixid.id; - } else if (dom_sid_compare_domain(&ace_nt->trustee, - &global_sid_Unix_NFS) == 0) { - return false; - } else { - DEBUG(1, ("nfs4_acls.c: could not " - "convert %s to uid or gid\n", - dom_sid_str_buf(&ace_nt->trustee, &buf))); + break; + case ID_TYPE_NOT_SPECIFIED: + default: + DBG_WARNING("Could not convert %s to uid or gid.\n", + dom_sid_str_buf(&ace_nt->trustee, &buf)); return false; } } -- 2.17.1 From e08f9b24097f8b5d08dcca3ee98017b114fcea99 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 25 Jun 2019 15:21:06 -0700 Subject: [PATCH 053/376] nfs4_acls: Use correct type when checking ownerGID uid and gid are members of the same union so this makes no difference, but for type correctness and readability use the gid to check for ownerGID. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 3b3d722ce579c19c7b08d06a3adea275537545dc) --- source3/modules/nfs4_acls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index f8861e9058b..b2ba4d1d701 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -856,7 +856,7 @@ static int smbacl4_substitute_simple( if (!(ace->flags & SMB_ACE4_ID_SPECIAL) && ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP && - ace->who.uid == ownerGID && + ace->who.gid == ownerGID && !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) && !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) && !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) { -- 2.17.1 From 6661fecf2676fc0ff30a86a2332be95fa76f89ed Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 26 Jun 2019 13:20:17 -0700 Subject: [PATCH 054/376] nfs4_acls: Add helper function for checking INHERIT flags. This avoids some code duplication. Do not make this static, as it will be used in a later patch. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmit Reviewed-by: Ralph Boehme (cherry picked from commit 336e8668c1cc3682cb3c198eb6dc49baf522a79a) --- source3/modules/nfs4_acls.c | 15 +++++++++------ source3/modules/nfs4_acls.h | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index b2ba4d1d701..bab73a5cb58 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -255,6 +255,13 @@ bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags) return true; } +bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace) +{ + return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE| + SMB_ACE4_FILE_INHERIT_ACE| + SMB_ACE4_DIRECTORY_INHERIT_ACE); +} + static int smbacl4_GetFileOwner(struct connection_struct *conn, const struct smb_filename *smb_fname, SMB_STRUCT_STAT *psbuf) @@ -846,9 +853,7 @@ static int smbacl4_substitute_simple( if (!(ace->flags & SMB_ACE4_ID_SPECIAL) && !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) && ace->who.uid == ownerUID && - !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) && - !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) && - !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) { + !nfs_ace_is_inherit(ace)) { ace->flags |= SMB_ACE4_ID_SPECIAL; ace->who.special_id = SMB_ACE4_WHO_OWNER; DEBUG(10,("replaced with special owner ace\n")); @@ -857,9 +862,7 @@ static int smbacl4_substitute_simple( if (!(ace->flags & SMB_ACE4_ID_SPECIAL) && ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP && ace->who.gid == ownerGID && - !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) && - !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) && - !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) { + !nfs_ace_is_inherit(ace)) { ace->flags |= SMB_ACE4_ID_SPECIAL; ace->who.special_id = SMB_ACE4_WHO_GROUP; DEBUG(10,("replaced with special group ace\n")); diff --git a/source3/modules/nfs4_acls.h b/source3/modules/nfs4_acls.h index a73b3154f0f..d0cf2d0f1fb 100644 --- a/source3/modules/nfs4_acls.h +++ b/source3/modules/nfs4_acls.h @@ -143,6 +143,8 @@ uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *theacl); bool smbacl4_set_controlflags(struct SMB4ACL_T *theacl, uint16_t controlflags); +bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace); + NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp, const struct smbacl4_vfs_params *pparams, uint32_t security_info, -- 2.17.1 From d5965e3a43f097a04d6ef14467f31b0c1d05a3b9 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 13:20:44 -0700 Subject: [PATCH 055/376] nfs4_acls: Add missing braces in smbacl4_win2nfs4 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit ba73d2363d93a376ba4947963c9de45a7e683f02) --- source3/modules/nfs4_acls.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index bab73a5cb58..11cb80e9300 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -905,12 +905,14 @@ static struct SMB4ACL_T *smbacl4_win2nfs4( if (pparams->acedup!=e_dontcare) { if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl, - &ace_v4, &addNewACE, i)) + &ace_v4, &addNewACE, i)) { return NULL; + } } - if (addNewACE) + if (addNewACE) { smb_add_ace4(theacl, &ace_v4); + } } if (pparams->mode==e_simple) { -- 2.17.1 From 428579d3fde2241a6280fae704dfda030397ff9c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 15 Jul 2019 14:43:01 -0700 Subject: [PATCH 056/376] nfs4_acls: Remove i argument from smbacl4_MergeIgnoreReject This is only used for logging of a rejected ACL, but does not provide additional useful information. Remove it to simplify the function a bit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 44790721e4f2c6ee6f46de7ac88123ce1a9f6e39) --- source3/modules/nfs4_acls.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 11cb80e9300..2317e0bc8b1 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -765,13 +765,10 @@ static bool smbacl4_fill_ace4( return true; /* OK */ } -static int smbacl4_MergeIgnoreReject( - enum smbacl4_acedup_enum acedup, - struct SMB4ACL_T *theacl, /* may modify it */ - SMB_ACE4PROP_T *ace, /* the "new" ACE */ - bool *paddNewACE, - int i -) +static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup, + struct SMB4ACL_T *theacl, + SMB_ACE4PROP_T *ace, + bool *paddNewACE) { int result = 0; SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace); @@ -788,7 +785,7 @@ static int smbacl4_MergeIgnoreReject( *paddNewACE = false; break; case e_reject: /* do an error */ - DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i)); + DBG_INFO("ACL rejected by duplicate nt ace.\n"); errno = EINVAL; /* SHOULD be set on any _real_ error */ result = -1; break; @@ -905,7 +902,7 @@ static struct SMB4ACL_T *smbacl4_win2nfs4( if (pparams->acedup!=e_dontcare) { if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl, - &ace_v4, &addNewACE, i)) { + &ace_v4, &addNewACE)) { return NULL; } } -- 2.17.1 From d806dba002c7ebe50e6b74fe2d43daadd0bbf05f Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 16 Jul 2019 15:20:25 -0700 Subject: [PATCH 057/376] nfs4_acls: Move smbacl4_MergeIgnoreReject function This static function will be called earlier in later patches. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 3499d97463110f042415d917160bc2743805a544) --- source3/modules/nfs4_acls.c | 61 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 2317e0bc8b1..cb407c6e032 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -654,6 +654,36 @@ static SMB_ACE4PROP_T *smbacl4_find_equal_special( return NULL; } +static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup, + struct SMB4ACL_T *theacl, + SMB_ACE4PROP_T *ace, + bool *paddNewACE) +{ + int result = 0; + SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace); + if (ace4found) + { + switch(acedup) + { + case e_merge: /* "merge" flags */ + *paddNewACE = false; + ace4found->aceFlags |= ace->aceFlags; + ace4found->aceMask |= ace->aceMask; + break; + case e_ignore: /* leave out this record */ + *paddNewACE = false; + break; + case e_reject: /* do an error */ + DBG_INFO("ACL rejected by duplicate nt ace.\n"); + errno = EINVAL; /* SHOULD be set on any _real_ error */ + result = -1; + break; + default: + break; + } + } + return result; +} static bool smbacl4_fill_ace4( bool is_directory, @@ -765,37 +795,6 @@ static bool smbacl4_fill_ace4( return true; /* OK */ } -static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup, - struct SMB4ACL_T *theacl, - SMB_ACE4PROP_T *ace, - bool *paddNewACE) -{ - int result = 0; - SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace); - if (ace4found) - { - switch(acedup) - { - case e_merge: /* "merge" flags */ - *paddNewACE = false; - ace4found->aceFlags |= ace->aceFlags; - ace4found->aceMask |= ace->aceMask; - break; - case e_ignore: /* leave out this record */ - *paddNewACE = false; - break; - case e_reject: /* do an error */ - DBG_INFO("ACL rejected by duplicate nt ace.\n"); - errno = EINVAL; /* SHOULD be set on any _real_ error */ - result = -1; - break; - default: - break; - } - } - return result; -} - static int smbacl4_substitute_special( struct SMB4ACL_T *acl, uid_t ownerUID, -- 2.17.1 From 693aa2dbfc84631be913a364dad57a12dae3c5ba Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 16 Jul 2019 15:30:36 -0700 Subject: [PATCH 058/376] nfs4_acls: Move adding of NFS4 ACE to ACL to smbacl4_fill_ace4 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit abb58b17599bd3f9a06037e208dcc5033c7fdd8b) --- source3/modules/nfs4_acls.c | 68 +++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index cb407c6e032..bab4dd0fd64 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -685,16 +685,41 @@ static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup, return result; } -static bool smbacl4_fill_ace4( +static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup, + struct SMB4ACL_T *nfs4_acl, + SMB_ACE4PROP_T *nfs4_ace) +{ + bool add_ace = true; + + if (acedup != e_dontcare) { + int ret; + + ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl, + nfs4_ace, &add_ace); + if (ret == -1) { + return -1; + } + } + + if (add_ace) { + smb_add_ace4(nfs4_acl, nfs4_ace); + } + + return 0; +} + +static int smbacl4_fill_ace4( bool is_directory, const struct smbacl4_vfs_params *params, uid_t ownerUID, gid_t ownerGID, const struct security_ace *ace_nt, /* input */ - SMB_ACE4PROP_T *ace_v4 /* output */ + struct SMB4ACL_T *nfs4_acl ) { struct dom_sid_buf buf; + SMB_ACE4PROP_T nfs4_ace = { 0 }; + SMB_ACE4PROP_T *ace_v4 = &nfs4_ace; DEBUG(10, ("got ace for %s\n", dom_sid_str_buf(&ace_nt->trustee, &buf))); @@ -742,7 +767,7 @@ static bool smbacl4_fill_ace4( ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE; if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE) && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) { - return false; + return 0; } } else if (params->mode!=e_special && dom_sid_equal(&ace_nt->trustee, @@ -754,7 +779,7 @@ static bool smbacl4_fill_ace4( ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE; if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE) && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) { - return false; + return 0; } } else { struct unixid unixid; @@ -764,12 +789,12 @@ static bool smbacl4_fill_ace4( if (!ok) { DBG_WARNING("Could not convert %s to uid or gid.\n", dom_sid_str_buf(&ace_nt->trustee, &buf)); - return false; + return 0; } if (dom_sid_compare_domain(&ace_nt->trustee, &global_sid_Unix_NFS) == 0) { - return false; + return 0; } switch (unixid.type) { @@ -788,11 +813,11 @@ static bool smbacl4_fill_ace4( default: DBG_WARNING("Could not convert %s to uid or gid.\n", dom_sid_str_buf(&ace_nt->trustee, &buf)); - return false; + return 0; } } - return true; /* OK */ + return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace); } static int smbacl4_substitute_special( @@ -886,28 +911,13 @@ static struct SMB4ACL_T *smbacl4_win2nfs4( return NULL; for(i=0; inum_aces; i++) { - SMB_ACE4PROP_T ace_v4; - bool addNewACE = true; - - if (!smbacl4_fill_ace4(is_directory, pparams, - ownerUID, ownerGID, - dacl->aces + i, &ace_v4)) { - struct dom_sid_buf buf; - DEBUG(3, ("Could not fill ace for file, SID %s\n", - dom_sid_str_buf(&((dacl->aces+i)->trustee), - &buf))); - continue; - } - - if (pparams->acedup!=e_dontcare) { - if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl, - &ace_v4, &addNewACE)) { - return NULL; - } - } + int ret; - if (addNewACE) { - smb_add_ace4(theacl, &ace_v4); + ret = smbacl4_fill_ace4(is_directory, pparams, + ownerUID, ownerGID, + dacl->aces + i, theacl); + if (ret == -1) { + return NULL; } } -- 2.17.1 From b3aad3426a87d41e0fc51129a9ef2d22a4e86ab3 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 16 Jul 2019 15:50:36 -0700 Subject: [PATCH 059/376] nfs4_acls: Remove redundant logging from smbacl4_fill_ace4 Logging flags in case they do not match seems unnecessary. Other log messages should show the flags as well. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 7ab0003ffc098247c3ee3962d7061f2af5a2d00e) --- source3/modules/nfs4_acls.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index bab4dd0fd64..25bcc770095 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -746,14 +746,6 @@ static int smbacl4_fill_ace4( se_map_generic(&ace_v4->aceMask, &file_generic_mapping); - if (ace_v4->aceFlags!=ace_nt->flags) - DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n", - ace_v4->aceFlags, ace_nt->flags)); - - if (ace_v4->aceMask!=ace_nt->access_mask) - DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n", - ace_v4->aceMask, ace_nt->access_mask)); - if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) { ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE; ace_v4->flags |= SMB_ACE4_ID_SPECIAL; -- 2.17.1 From 01e913caf03078b06592f6b66b737223896b4385 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 16 Jul 2019 15:56:12 -0700 Subject: [PATCH 060/376] nfs4_acls: Remove redundant pointer variable The previous patch introduced a pointer to a local variable to reduce the amount of lines changed. Remove that pointer and adjust all usage accordingly. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit aa4644193635d846c2e08e8c1e7b512e8009c2ef) --- source3/modules/nfs4_acls.c | 56 +++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 25bcc770095..d169377295a 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -719,58 +719,54 @@ static int smbacl4_fill_ace4( { struct dom_sid_buf buf; SMB_ACE4PROP_T nfs4_ace = { 0 }; - SMB_ACE4PROP_T *ace_v4 = &nfs4_ace; DEBUG(10, ("got ace for %s\n", dom_sid_str_buf(&ace_nt->trustee, &buf))); - ZERO_STRUCTP(ace_v4); - /* only ACCESS|DENY supported right now */ - ace_v4->aceType = ace_nt->type; + nfs4_ace.aceType = ace_nt->type; - ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags( - ace_nt->flags); + nfs4_ace.aceFlags = + map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags); /* remove inheritance flags on files */ if (!is_directory) { DEBUG(10, ("Removing inheritance flags from a file\n")); - ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE| - SMB_ACE4_DIRECTORY_INHERIT_ACE| - SMB_ACE4_NO_PROPAGATE_INHERIT_ACE| - SMB_ACE4_INHERIT_ONLY_ACE); + nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE| + SMB_ACE4_DIRECTORY_INHERIT_ACE| + SMB_ACE4_NO_PROPAGATE_INHERIT_ACE| + SMB_ACE4_INHERIT_ONLY_ACE); } - ace_v4->aceMask = ace_nt->access_mask & - (SEC_STD_ALL | SEC_FILE_ALL); + nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL); - se_map_generic(&ace_v4->aceMask, &file_generic_mapping); + se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping); if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) { - ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE; - ace_v4->flags |= SMB_ACE4_ID_SPECIAL; + nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE; + nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL; } else if (params->mode!=e_special && dom_sid_equal(&ace_nt->trustee, &global_sid_Creator_Owner)) { DEBUG(10, ("Map creator owner\n")); - ace_v4->who.special_id = SMB_ACE4_WHO_OWNER; - ace_v4->flags |= SMB_ACE4_ID_SPECIAL; + nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER; + nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL; /* A non inheriting creator owner entry has no effect. */ - ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE; - if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE) - && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) { + nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE; + if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE) + && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) { return 0; } } else if (params->mode!=e_special && dom_sid_equal(&ace_nt->trustee, &global_sid_Creator_Group)) { DEBUG(10, ("Map creator owner group\n")); - ace_v4->who.special_id = SMB_ACE4_WHO_GROUP; - ace_v4->flags |= SMB_ACE4_ID_SPECIAL; + nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP; + nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL; /* A non inheriting creator group entry has no effect. */ - ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE; - if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE) - && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) { + nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE; + if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE) + && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) { return 0; } } else { @@ -791,15 +787,15 @@ static int smbacl4_fill_ace4( switch (unixid.type) { case ID_TYPE_BOTH: - ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; - ace_v4->who.gid = unixid.id; + nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; + nfs4_ace.who.gid = unixid.id; break; case ID_TYPE_GID: - ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; - ace_v4->who.gid = unixid.id; + nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; + nfs4_ace.who.gid = unixid.id; break; case ID_TYPE_UID: - ace_v4->who.uid = unixid.id; + nfs4_ace.who.uid = unixid.id; break; case ID_TYPE_NOT_SPECIFIED: default: -- 2.17.1 From 8ac9c1f75f3f01370c9dba5d570f95c48e2029b4 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 17 Jul 2019 10:49:47 -0700 Subject: [PATCH 061/376] nfs4_acls: Add additional owner entry when mapping to NFS4 ACL with IDMAP_TYPE_BOTH With IDMAP_TYPE_BOTH, all entries have to be mapped to group entries. In order to have the file system reflect the owner permissions in the POSIX modebits, create a second entry for the user. This will be mapped to the "special owner" entry. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit b796119e2df38d1935064556934dd10da6f3d339) --- source3/modules/nfs4_acls.c | 37 +++++++++++++++++++++++++++++- source3/modules/test_nfs4_acls.c | 39 +++++++++++++++++++++++++++----- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index d169377295a..70d725eb937 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -719,6 +719,9 @@ static int smbacl4_fill_ace4( { struct dom_sid_buf buf; SMB_ACE4PROP_T nfs4_ace = { 0 }; + SMB_ACE4PROP_T nfs4_ace_2 = { 0 }; + bool add_ace2 = false; + int ret; DEBUG(10, ("got ace for %s\n", dom_sid_str_buf(&ace_nt->trustee, &buf))); @@ -789,6 +792,29 @@ static int smbacl4_fill_ace4( case ID_TYPE_BOTH: nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; nfs4_ace.who.gid = unixid.id; + + if (ownerUID == unixid.id && + !nfs_ace_is_inherit(&nfs4_ace)) + { + /* + * IDMAP_TYPE_BOTH for owner. Add + * additional user entry, which can be + * mapped to special:owner to reflect + * the permissions in the modebits. + * + * This only applies to non-inheriting + * entries as only these are replaced + * with SPECIAL_OWNER in nfs4:mode=simple. + */ + nfs4_ace_2 = (SMB_ACE4PROP_T) { + .who.uid = unixid.id, + .aceFlags = (nfs4_ace.aceFlags & + ~SMB_ACE4_IDENTIFIER_GROUP), + .aceMask = nfs4_ace.aceMask, + .aceType = nfs4_ace.aceType, + }; + add_ace2 = true; + } break; case ID_TYPE_GID: nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; @@ -805,7 +831,16 @@ static int smbacl4_fill_ace4( } } - return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace); + ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace); + if (ret != 0) { + return -1; + } + + if (!add_ace2) { + return 0; + } + + return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2); } static int smbacl4_substitute_special( diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index d7152a0737a..170a397579a 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1671,6 +1671,7 @@ struct dacl_to_nfs4_idmap_both { uint32_t nfs4_flags; uint32_t nfs4_ace_flags; uint32_t nfs4_id; + int num_nfs4_aces; }; /* @@ -1684,13 +1685,17 @@ static void test_dacl_to_nfs4_idmap_type_both(void **state) struct dacl_to_nfs4_idmap_both dacl_to_nfs4_idmap_both[] = { { &sids[2], 0, - SMB_ACE4_ID_SPECIAL, SMB_ACE4_IDENTIFIER_GROUP, SMB_ACE4_WHO_GROUP }, + SMB_ACE4_ID_SPECIAL, SMB_ACE4_IDENTIFIER_GROUP, SMB_ACE4_WHO_GROUP, + 2 }, { &sids[2], SEC_ACE_FLAG_OBJECT_INHERIT, - 0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1002 }, + 0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1002, + 1 }, { &sids[6], 0, - 0, SMB_ACE4_IDENTIFIER_GROUP, 1005 }, + 0, SMB_ACE4_IDENTIFIER_GROUP, 1005, + 1 }, { &sids[6], SEC_ACE_FLAG_OBJECT_INHERIT, - 0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1005 }, + 0, SMB_ACE4_IDENTIFIER_GROUP|SMB_ACE4_FILE_INHERIT_ACE, 1005, + 1 }, }; for (i = 0; i < ARRAY_SIZE(dacl_to_nfs4_idmap_both); i++) { @@ -1720,11 +1725,11 @@ static void test_dacl_to_nfs4_idmap_type_both(void **state) assert_non_null(nfs4_acl); assert_int_equal(smbacl4_get_controlflags(nfs4_acl), SEC_DESC_SELF_RELATIVE); - assert_int_equal(smb_get_naces(nfs4_acl), 1); + assert_int_equal(smb_get_naces(nfs4_acl), + dacl_to_nfs4_idmap_both[i].num_nfs4_aces); nfs4_ace_container = smb_first_ace4(nfs4_acl); assert_non_null(nfs4_ace_container); - assert_null(smb_next_ace4(nfs4_ace_container)); nfs4_ace = smb_get_ace4(nfs4_ace_container); assert_int_equal(nfs4_ace->flags, @@ -1744,6 +1749,28 @@ static void test_dacl_to_nfs4_idmap_type_both(void **state) assert_int_equal(nfs4_ace->aceType, SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE); assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + + if (dacl_to_nfs4_idmap_both[i].num_nfs4_aces == 2) { + nfs4_ace_container = smb_next_ace4(nfs4_ace_container); + assert_non_null(nfs4_ace_container); + + nfs4_ace = smb_get_ace4(nfs4_ace_container); + assert_int_equal(nfs4_ace->flags, + dacl_to_nfs4_idmap_both[i].nfs4_flags); + assert_int_equal(nfs4_ace->aceFlags, + dacl_to_nfs4_idmap_both[i].nfs4_ace_flags & + ~SMB_ACE4_IDENTIFIER_GROUP); + if (nfs4_ace->flags & SMB_ACE4_ID_SPECIAL) { + assert_int_equal(nfs4_ace->who.special_id, + SMB_ACE4_WHO_OWNER); + } else { + assert_int_equal(nfs4_ace->who.uid, + dacl_to_nfs4_idmap_both[i].nfs4_id); + } + assert_int_equal(nfs4_ace->aceType, + SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE); + assert_int_equal(nfs4_ace->aceMask, SMB_ACE4_READ_DATA); + } } TALLOC_FREE(frame); -- 2.17.1 From 7d40b00bac82d8cd185850aa1b8a13c5f79848d7 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 18 Jul 2019 11:49:29 -0700 Subject: [PATCH 062/376] nfs4_acls: Rename smbacl4_fill_ace4 function As this function now maps the ACE and also adds it to the NFSv4 ACE, change the name to better describe its behavior. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 169812943de23cf2752289c63331d786b0b063bd) --- source3/modules/nfs4_acls.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 70d725eb937..663fcba67aa 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -708,14 +708,12 @@ static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup, return 0; } -static int smbacl4_fill_ace4( - bool is_directory, - const struct smbacl4_vfs_params *params, - uid_t ownerUID, - gid_t ownerGID, - const struct security_ace *ace_nt, /* input */ - struct SMB4ACL_T *nfs4_acl -) +static int nfs4_acl_add_sec_ace(bool is_directory, + const struct smbacl4_vfs_params *params, + uid_t ownerUID, + gid_t ownerGID, + const struct security_ace *ace_nt, + struct SMB4ACL_T *nfs4_acl) { struct dom_sid_buf buf; SMB_ACE4PROP_T nfs4_ace = { 0 }; @@ -936,9 +934,9 @@ static struct SMB4ACL_T *smbacl4_win2nfs4( for(i=0; inum_aces; i++) { int ret; - ret = smbacl4_fill_ace4(is_directory, pparams, - ownerUID, ownerGID, - dacl->aces + i, theacl); + ret = nfs4_acl_add_sec_ace(is_directory, pparams, + ownerUID, ownerGID, + dacl->aces + i, theacl); if (ret == -1) { return NULL; } -- 2.17.1 From 78d426fb0d4f9332e9c0a084993b5f2f5e0cdc40 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 2 Jul 2019 15:08:11 -0700 Subject: [PATCH 063/376] nfs4_acls: Remove duplicate entries when mapping from NFS4 ACL to DACL The previous patch added an additional entry for IDMAP_TYPE_BOTH. When mapping back to a DACL, there should be no additional entry. Add a loop that will check and remove entries that are exact duplicates. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 9c88602128592ddad537bf70cbe3c51f0b2cebe5) --- source3/modules/nfs4_acls.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 663fcba67aa..74b66a2c392 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -297,6 +297,35 @@ static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf) return 0; } +static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list, + int *good_aces) +{ + struct security_ace *last = NULL; + int i; + + if (*good_aces < 2) { + return; + } + + last = &nt_ace_list[(*good_aces) - 1]; + + for (i = 0; i < (*good_aces) - 1; i++) { + struct security_ace *cur = &nt_ace_list[i]; + + if (cur->type == last->type && + cur->flags == last->flags && + cur->access_mask == last->access_mask && + dom_sid_equal(&cur->trustee, &last->trustee)) + { + struct dom_sid_buf sid_buf; + + DBG_INFO("Removing duplicate entry for SID %s.\n", + dom_sid_str_buf(&last->trustee, &sid_buf)); + (*good_aces)--; + } + } +} + static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, const struct smbacl4_vfs_params *params, struct SMB4ACL_T *acl, /* in */ @@ -438,6 +467,8 @@ static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx, ace->aceType, mask, win_ace_flags); } + + check_for_duplicate_sec_ace(nt_ace_list, &good_aces); } nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace, -- 2.17.1 From 77052fbc65a375dc5a3dda4ac9d212b808ca802f Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 10 Jul 2019 13:14:32 -0700 Subject: [PATCH 064/376] nfs4_acls: Add test for merging duplicates when mapping from NFS4 ACL to DACL The previous patch introduced merging of duplicates on the mapping path from NFS4 ACL entries to DACL entries. Add a testcase to verify the expected behavior of this codepath. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 1a137a2f20c2f159c5feaef230a2b85bb9fb23b5) --- source3/modules/test_nfs4_acls.c | 79 ++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/source3/modules/test_nfs4_acls.c b/source3/modules/test_nfs4_acls.c index 170a397579a..0b23bd1d02e 100644 --- a/source3/modules/test_nfs4_acls.c +++ b/source3/modules/test_nfs4_acls.c @@ -1776,6 +1776,84 @@ static void test_dacl_to_nfs4_idmap_type_both(void **state) TALLOC_FREE(frame); } +static void test_nfs4_to_dacl_remove_duplicate(void **state) +{ + + struct dom_sid *sids = *state; + TALLOC_CTX *frame = talloc_stackframe(); + struct SMB4ACL_T *nfs4_acl; + SMB_ACE4PROP_T nfs4_ace; + struct security_ace *dacl_aces; + int good_aces; + struct smbacl4_vfs_params params = { + .mode = e_simple, + .do_chown = true, + .acedup = e_dontcare, + .map_full_control = true, + }; + + nfs4_acl = smb_create_smb4acl(frame); + assert_non_null(nfs4_acl); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .who.uid = 1002, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = SMB_ACE4_INHERITED_ACE, + .aceMask = SMB_ACE4_WRITE_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .who.gid = 1002, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = SMB_ACE4_IDENTIFIER_GROUP| + SMB_ACE4_INHERITED_ACE, + .aceMask = SMB_ACE4_WRITE_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .who.gid = 1002, + .aceType = SMB_ACE4_ACCESS_DENIED_ACE_TYPE, + .aceFlags = SMB_ACE4_IDENTIFIER_GROUP| + SMB_ACE4_INHERITED_ACE, + .aceMask = SMB_ACE4_WRITE_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + nfs4_ace = (SMB_ACE4PROP_T) { + .flags = 0, + .who.gid = 1002, + .aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE, + .aceFlags = SMB_ACE4_IDENTIFIER_GROUP| + SMB_ACE4_INHERITED_ACE, + .aceMask = SMB_ACE4_WRITE_DATA, + }; + assert_non_null(smb_add_ace4(nfs4_acl, &nfs4_ace)); + + assert_true(smbacl4_nfs42win(frame, ¶ms, nfs4_acl, + &sids[0], &sids[1], true, + &dacl_aces, &good_aces)); + + assert_int_equal(good_aces, 2); + assert_non_null(dacl_aces); + + assert_int_equal(dacl_aces[0].type, SEC_ACE_TYPE_ACCESS_ALLOWED); + assert_int_equal(dacl_aces[0].flags, SEC_ACE_FLAG_INHERITED_ACE); + assert_int_equal(dacl_aces[0].access_mask, SEC_FILE_WRITE_DATA); + assert_true(dom_sid_equal(&dacl_aces[0].trustee, &sids[2])); + + assert_int_equal(dacl_aces[1].type, SEC_ACE_TYPE_ACCESS_DENIED); + assert_int_equal(dacl_aces[1].flags, SEC_ACE_FLAG_INHERITED_ACE); + assert_int_equal(dacl_aces[1].access_mask, SEC_FILE_WRITE_DATA); + assert_true(dom_sid_equal(&dacl_aces[1].trustee, &sids[2])); + + TALLOC_FREE(frame); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { @@ -1799,6 +1877,7 @@ int main(int argc, char **argv) cmocka_unit_test(test_nfs4_to_dacl_config_special), cmocka_unit_test(test_nfs4_to_dacl_idmap_type_both), cmocka_unit_test(test_dacl_to_nfs4_idmap_type_both), + cmocka_unit_test(test_nfs4_to_dacl_remove_duplicate), }; cmocka_set_message_output(CM_OUTPUT_SUBUNIT); -- 2.17.1 From d186689038c5f807b092f63d7f89fd6b6dd95241 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 17 Jul 2019 15:29:06 -0700 Subject: [PATCH 065/376] nfs4_acls: Use correct owner information for ACL after owner change After a chown, the cached stat data is obviously no longer valid. The code in smb_set_nt_acl_nfs4 checked the file correctly, but did only use a local buffer for the stat data. So later checks of the stat buffer under the fsp->fsp_name->st would still see the old information. Fix this by removing the local stat buffer and always update the one under fsp->fsp_name->st. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 86f7af84f04b06ed96b30f936ace92aa0937be06) --- source3/modules/nfs4_acls.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index 74b66a2c392..eb76696948b 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -994,11 +994,11 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp, struct SMB4ACL_T *theacl = NULL; bool result, is_directory; - SMB_STRUCT_STAT sbuf; bool set_acl_as_root = false; uid_t newUID = (uid_t)-1; gid_t newGID = (gid_t)-1; int saved_errno; + NTSTATUS status; TALLOC_CTX *frame = talloc_stackframe(); DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp))); @@ -1022,25 +1022,29 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp, pparams = ¶ms; } - if (smbacl4_fGetFileOwner(fsp, &sbuf)) { + status = vfs_stat_fsp(fsp); + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); - return map_nt_error_from_unix(errno); + return status; } - is_directory = S_ISDIR(sbuf.st_ex_mode); + is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode); if (pparams->do_chown) { /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */ - NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID, - security_info_sent, psd); + + uid_t old_uid = fsp->fsp_name->st.st_ex_uid; + uid_t old_gid = fsp->fsp_name->st.st_ex_uid; + status = unpack_nt_owners(fsp->conn, &newUID, &newGID, + security_info_sent, psd); if (!NT_STATUS_IS_OK(status)) { DEBUG(8, ("unpack_nt_owners failed")); TALLOC_FREE(frame); return status; } - if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) || - ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) { - + if (((newUID != (uid_t)-1) && (old_uid != newUID)) || + ((newGID != (gid_t)-1) && (old_gid != newGID))) + { status = try_chown(fsp, newUID, newGID); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("chown %s, %u, %u failed. Error = " @@ -1055,11 +1059,14 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp, DEBUG(10,("chown %s, %u, %u succeeded.\n", fsp_str_dbg(fsp), (unsigned int)newUID, (unsigned int)newGID)); - if (smbacl4_GetFileOwner(fsp->conn, - fsp->fsp_name, - &sbuf)){ + + /* + * Owner change, need to update stat info. + */ + status = vfs_stat_fsp(fsp); + if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(frame); - return map_nt_error_from_unix(errno); + return status; } /* If we successfully chowned, we know we must @@ -1077,7 +1084,8 @@ NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp, } theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams, - sbuf.st_ex_uid, sbuf.st_ex_gid); + fsp->fsp_name->st.st_ex_uid, + fsp->fsp_name->st.st_ex_gid); if (!theacl) { TALLOC_FREE(frame); return map_nt_error_from_unix(errno); -- 2.17.1 From 7c90ecdb15cc6d572a37c2d435b6c7d86559d944 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 9 Jul 2019 12:04:35 -0700 Subject: [PATCH 066/376] vfs_gpfs: Remove merge_writeappend parameter All supported GPFS versions now support setting WRITE and APPEND in the ACLs independently. Remove this now unused parameter to simplify the code. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 0aca678fcf1788a76cf0ff11399211c795aa7d2f) --- source3/modules/vfs_gpfs.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 4b963edab11..72c06a6dcb1 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -708,29 +708,6 @@ static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx, gace->aceType = aceprop->aceType; gace->aceFlags = aceprop->aceFlags; gace->aceMask = aceprop->aceMask; - - /* - * GPFS can't distinguish between WRITE and APPEND on - * files, so one being set without the other is an - * error. Sorry for the many ()'s :-) - */ - - if (!fsp->is_directory - && - ((((gace->aceMask & ACE4_MASK_WRITE) == 0) - && ((gace->aceMask & ACE4_MASK_APPEND) != 0)) - || - (((gace->aceMask & ACE4_MASK_WRITE) != 0) - && ((gace->aceMask & ACE4_MASK_APPEND) == 0))) - && - lp_parm_bool(fsp->conn->params->service, "gpfs", - "merge_writeappend", True)) { - DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains " - "WRITE^APPEND, setting WRITE|APPEND\n", - fsp_str_dbg(fsp))); - gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND; - } - gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0; if (aceprop->flags&SMB_ACE4_ID_SPECIAL) -- 2.17.1 From 90ddc22ea5552b7d3a2c4cc7cb1b75e3ef1e52f2 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 10 Jul 2019 11:06:19 -0700 Subject: [PATCH 067/376] docs: Remove gpfs:merge_writeappend from vfs_gpfs manpage BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit 8bd79ecc37376dbaa35606f9c2777653eb3d55e3) --- docs-xml/manpages/vfs_gpfs.8.xml | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/docs-xml/manpages/vfs_gpfs.8.xml b/docs-xml/manpages/vfs_gpfs.8.xml index 2f3b4274e4b..fb1f5bb2237 100644 --- a/docs-xml/manpages/vfs_gpfs.8.xml +++ b/docs-xml/manpages/vfs_gpfs.8.xml @@ -204,26 +204,6 @@ - gpfs:merge_writeappend = [ yes | no ] - - - GPFS ACLs doesn't know about the 'APPEND' right. - This option lets Samba map the 'APPEND' right to 'WRITE'. - - - - - yes(default) - map 'APPEND' to 'WRITE'. - - - no - do not map 'APPEND' to 'WRITE'. - - - - - - - gpfs:acl = [ yes | no ] -- 2.17.1 From 39495b14cdd228c842666222952ad789e63977ef Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 9 Jul 2019 13:08:35 -0700 Subject: [PATCH 068/376] vfs_gpfs: Move mapping from generic NFSv ACL to GPFS ACL to separate function This is not functional change. It cleans up the code a bit and makes expanding this codepath in a later patch easier. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit fbf3a090a9ec94262b2924461cc1d6336af9919c) --- source3/modules/vfs_gpfs.c | 69 ++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 72c06a6dcb1..d0dc1ddb173 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -672,6 +672,43 @@ static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle, return map_nt_error_from_unix(errno); } +static bool vfs_gpfs_nfs4_ace_to_gpfs_ace(SMB_ACE4PROP_T *nfs4_ace, + struct gpfs_ace_v4 *gace) +{ + gace->aceType = nfs4_ace->aceType; + gace->aceFlags = nfs4_ace->aceFlags; + gace->aceMask = nfs4_ace->aceMask; + + if (nfs4_ace->flags & SMB_ACE4_ID_SPECIAL) { + switch(nfs4_ace->who.special_id) { + case SMB_ACE4_WHO_EVERYONE: + gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID; + gace->aceWho = ACE4_SPECIAL_EVERYONE; + break; + case SMB_ACE4_WHO_OWNER: + gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID; + gace->aceWho = ACE4_SPECIAL_OWNER; + break; + case SMB_ACE4_WHO_GROUP: + gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID; + gace->aceWho = ACE4_SPECIAL_GROUP; + break; + default: + DBG_WARNING("Unsupported special_id %d\n", + nfs4_ace->who.special_id); + return false; + } + + return true; + } + + gace->aceIFlags = 0; + gace->aceWho = (nfs4_ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) ? + nfs4_ace->who.gid : nfs4_ace->who.uid; + + return true; +} + static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx, files_struct *fsp, struct SMB4ACL_T *smbacl, @@ -704,35 +741,11 @@ static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx, for (smbace=smb_first_ace4(smbacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) { struct gpfs_ace_v4 *gace = gpfs_ace_ptr(gacl, gacl->acl_nace); SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace); + bool add_ace; - gace->aceType = aceprop->aceType; - gace->aceFlags = aceprop->aceFlags; - gace->aceMask = aceprop->aceMask; - gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0; - - if (aceprop->flags&SMB_ACE4_ID_SPECIAL) - { - switch(aceprop->who.special_id) - { - case SMB_ACE4_WHO_EVERYONE: - gace->aceWho = ACE4_SPECIAL_EVERYONE; - break; - case SMB_ACE4_WHO_OWNER: - gace->aceWho = ACE4_SPECIAL_OWNER; - break; - case SMB_ACE4_WHO_GROUP: - gace->aceWho = ACE4_SPECIAL_GROUP; - break; - default: - DEBUG(8, ("unsupported special_id %d\n", aceprop->who.special_id)); - continue; /* don't add it !!! */ - } - } else { - /* just only for the type safety... */ - if (aceprop->aceFlags&SMB_ACE4_IDENTIFIER_GROUP) - gace->aceWho = aceprop->who.gid; - else - gace->aceWho = aceprop->who.uid; + add_ace = vfs_gpfs_nfs4_ace_to_gpfs_ace(aceprop, gace); + if (!add_ace) { + continue; } gacl->acl_nace++; -- 2.17.1 From d18896d19988b1096849c00a80dda42a727d5c4c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 9 Jul 2019 13:39:55 -0700 Subject: [PATCH 069/376] vfs_gpfs: Implement special case for denying owner access to ACL In GPFS, it is not possible to deny ACL or attribute access through a SPECIAL_OWNER entry. The best that can be done is mapping this to a named user entry, as this one can at least be stored in an ACL. The same cannot be done for inheriting SPECIAL_OWNER entries, as these represent CREATOR OWNER entries, and the limitation of not being able to deny owner access to ACL or attributes remains. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14032 Signed-off-by: Christof Schmitt Reviewed-by: Ralph Boehme (cherry picked from commit c1770ed96fd3137f45d584ba9328333d5505e3af) --- source3/modules/vfs_gpfs.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index d0dc1ddb173..f0d5074d36b 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -673,7 +673,8 @@ static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle, } static bool vfs_gpfs_nfs4_ace_to_gpfs_ace(SMB_ACE4PROP_T *nfs4_ace, - struct gpfs_ace_v4 *gace) + struct gpfs_ace_v4 *gace, + uid_t owner_uid) { gace->aceType = nfs4_ace->aceType; gace->aceFlags = nfs4_ace->aceFlags; @@ -686,8 +687,35 @@ static bool vfs_gpfs_nfs4_ace_to_gpfs_ace(SMB_ACE4PROP_T *nfs4_ace, gace->aceWho = ACE4_SPECIAL_EVERYONE; break; case SMB_ACE4_WHO_OWNER: - gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID; - gace->aceWho = ACE4_SPECIAL_OWNER; + /* + * With GPFS it is not possible to deny ACL or + * attribute access to the owner. Setting an + * ACL with such an entry is not possible. + * Denying ACL or attribute access for the + * owner through a named ACL entry can be + * stored in an ACL, it is just not effective. + * + * Map this case to a named entry to allow at + * least setting this ACL, which will be + * enforced by the smbd permission check. Do + * not do this for an inheriting OWNER entry, + * as this represents a CREATOR OWNER ACE. The + * remaining limitation is that CREATOR OWNER + * cannot deny ACL or attribute access. + */ + if (!nfs_ace_is_inherit(nfs4_ace) && + nfs4_ace->aceType == + SMB_ACE4_ACCESS_DENIED_ACE_TYPE && + nfs4_ace->aceMask & (SMB_ACE4_READ_ATTRIBUTES| + SMB_ACE4_WRITE_ATTRIBUTES| + SMB_ACE4_READ_ACL| + SMB_ACE4_WRITE_ACL)) { + gace->aceIFlags = 0; + gace->aceWho = owner_uid; + } else { + gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID; + gace->aceWho = ACE4_SPECIAL_OWNER; + } break; case SMB_ACE4_WHO_GROUP: gace->aceIFlags = ACE4_IFLAG_SPECIAL_ID; @@ -743,7 +771,8 @@ static struct gpfs_acl *vfs_gpfs_smbacl2gpfsacl(TALLOC_CTX *mem_ctx, SMB_ACE4PROP_T *aceprop = smb_get_ace4(smbace); bool add_ace; - add_ace = vfs_gpfs_nfs4_ace_to_gpfs_ace(aceprop, gace); + add_ace = vfs_gpfs_nfs4_ace_to_gpfs_ace(aceprop, gace, + fsp->fsp_name->st.st_ex_uid); if (!add_ace) { continue; } -- 2.17.1 From be508cda25d97b825fef3d605938faa3726cde44 Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Mon, 22 Jul 2019 15:29:03 +1200 Subject: [PATCH 070/376] downgradedatabase: comply with samba.tests.source In next commit we'll install the script, samba.tests.source picked up the lack of a copyright message and some whitespace errors, so this patch fixes that stuff first. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Aaron Haslett Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit c4aebb15001c830a46d5a6ad8ea11a6f9ea4fd04) --- source4/scripting/bin/sambadowngradedatabase | 26 +++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/source4/scripting/bin/sambadowngradedatabase b/source4/scripting/bin/sambadowngradedatabase index 9d1e2b8cc76..87a989bfd6a 100755 --- a/source4/scripting/bin/sambadowngradedatabase +++ b/source4/scripting/bin/sambadowngradedatabase @@ -1,4 +1,24 @@ -#!/usr/bin/env python3 +#!/usr/bin/python3 +# +# Unix SMB/CIFS implementation. +# Copyright (C) Andrew Bartlett 2019 +# +# Downgrade a database from 4.11 format to 4.7 format. 4.7 Format will +# run on any version of Samba AD, and Samba will repack/reconfigure the +# database if necessary. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . from __future__ import print_function import optparse import sys @@ -38,9 +58,9 @@ samdb = ldb.Ldb(url=url, options=["modules:"]) partitions = samdb.search(base="@PARTITION", - scope=ldb.SCOPE_BASE, + scope=ldb.SCOPE_BASE, attrs=["backendStore", "partition"]) - + backend = str(partitions[0].get('backendStore', 'tdb')) if backend == "mdb": -- 2.17.1 From 7a8f68f615034c696e90f86eb1670f4b100300fc Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Mon, 29 Jul 2019 13:35:08 +1200 Subject: [PATCH 071/376] tests: Avoid hardcoding relative filepath If we move the test file, the test will break. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit a8cdbe0b824f57f73eee09143148f009a9c58582) --- python/samba/tests/blackbox/downgradedatabase.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/blackbox/downgradedatabase.py b/python/samba/tests/blackbox/downgradedatabase.py index a5e540c1354..4a8411b1f1a 100644 --- a/python/samba/tests/blackbox/downgradedatabase.py +++ b/python/samba/tests/blackbox/downgradedatabase.py @@ -23,8 +23,8 @@ import shutil from subprocess import check_output from samba.samdb import SamDB -COMMAND = os.path.join(os.path.dirname(__file__), - "../../../../../source4/scripting/bin/sambadowngradedatabase") +COMMAND = os.path.join(os.environ.get("SRCDIR_ABS"), + "source4/scripting/bin/sambadowngradedatabase") class DowngradeTestBase(BlackboxTestCase): -- 2.17.1 From a1b3796b5643d7d727964751efb19675d5ee42c7 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Mon, 29 Jul 2019 13:39:04 +1200 Subject: [PATCH 072/376] downgradedatabase: rename to samba_downgrade_db Just so that it's slightly less of a mouthful for users. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit fdaaee8d3aac77d91642a7d75d4bcd15d4df8657) --- python/samba/tests/blackbox/downgradedatabase.py | 2 +- selftest/knownfail.d/usage | 2 +- .../bin/{sambadowngradedatabase => samba_downgrade_db} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename source4/scripting/bin/{sambadowngradedatabase => samba_downgrade_db} (100%) diff --git a/python/samba/tests/blackbox/downgradedatabase.py b/python/samba/tests/blackbox/downgradedatabase.py index 4a8411b1f1a..3d230609efc 100644 --- a/python/samba/tests/blackbox/downgradedatabase.py +++ b/python/samba/tests/blackbox/downgradedatabase.py @@ -24,7 +24,7 @@ from subprocess import check_output from samba.samdb import SamDB COMMAND = os.path.join(os.environ.get("SRCDIR_ABS"), - "source4/scripting/bin/sambadowngradedatabase") + "source4/scripting/bin/samba_downgrade_db") class DowngradeTestBase(BlackboxTestCase): diff --git a/selftest/knownfail.d/usage b/selftest/knownfail.d/usage index 23d52c0b727..0a495858e8c 100644 --- a/selftest/knownfail.d/usage +++ b/selftest/knownfail.d/usage @@ -25,7 +25,7 @@ samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_rebuildextendedd samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_renamedc.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_repl_cleartext_pwd_py.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_rodcdns.none. -samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_sambadowngradedatabase.none. +samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_samba_downgrade_db.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_samba_gpupdate.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_samba_gpupdate_.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_samba_kcc.none. diff --git a/source4/scripting/bin/sambadowngradedatabase b/source4/scripting/bin/samba_downgrade_db similarity index 100% rename from source4/scripting/bin/sambadowngradedatabase rename to source4/scripting/bin/samba_downgrade_db -- 2.17.1 From 309ec3b63c5d9f441bcc922e62c2f6a2c2907f62 Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Mon, 22 Jul 2019 13:35:21 +1200 Subject: [PATCH 073/376] downgradedatabase: Add man-page documentation A man-page is needed so that we can install this tool as part of the Samba package. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Aaron Haslett Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit c89df3862b17fad9c4648b5d9c6805120d732df8) --- docs-xml/manpages/samba_downgrade_db.8.xml | 95 ++++++++++++++++++++++ docs-xml/wscript_build | 1 + 2 files changed, 96 insertions(+) create mode 100644 docs-xml/manpages/samba_downgrade_db.8.xml diff --git a/docs-xml/manpages/samba_downgrade_db.8.xml b/docs-xml/manpages/samba_downgrade_db.8.xml new file mode 100644 index 00000000000..7b0c822cf21 --- /dev/null +++ b/docs-xml/manpages/samba_downgrade_db.8.xml @@ -0,0 +1,95 @@ + + + + + + samba_downgrade_db + 8 + Samba + User Commands + &doc.version; + + + + + samba_downgrade_db + Samba tool for downgrading AD databases + + + + + + samba_downgrade_db + -H + -s + + + + + DESCRIPTION + This tool is part of the samba + 8 suite. + + The format of the Samba Active Directory (AD) database changed in + version 4.8 and 4.11. When downgrading a Samba AD Domain Controller (DC) + to a release that is older than either of these versions (e.g. 4.11 to + 4.10), the AD database must be manually downgraded + before the Samba packages can be safely downgraded. + + + This tool downgrades a Samba sam.ldb database from the format + used in version &doc.version; to that of version 4.7. The v4.7 database + format can safely be read by any version of Samba. If necessary, later + versions of Samba will repack and reconfigure a v4.7-format database when + the samba executable is first started. + + Note that all Samba services must be stopped on the DC before running + this tool. Once the tool has run, do not restart samba or modify the + database before the Samba software package has been downgraded. + + + + + OPTIONS + + + + + -H [sam.ldb file] + + Link directly to a sam.ldb file instead of using path in system + smb.conf + + + + + -s [smb.conf file] + + Link directly to smb.conf file instead of system default (usually + in /usr/local/samba/etc/smb.conf) + + + + + + + + VERSION + + This man page is complete for version &doc.version; of the Samba + suite. + + + + AUTHOR + + The original Samba software and related utilities + were created by Andrew Tridgell. Samba is now developed + by the Samba Team as an Open Source project similar + to the way the Linux kernel is developed. + + The samba_downgrade_db tool was developed by the Samba team + at Catalyst IT Ltd. + + + diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build index 575fb702b46..3dad0a21313 100644 --- a/docs-xml/wscript_build +++ b/docs-xml/wscript_build @@ -31,6 +31,7 @@ manpages=''' manpages/samba-tool.8 manpages/samba.7 manpages/samba.8 + manpages/samba_downgrade_db.8 manpages/sharesec.1 manpages/smbcacls.1 manpages/smbclient.1 -- 2.17.1 From b3987205fe2770bd88ae5ee8e10a85cebf662ac0 Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Mon, 22 Jul 2019 13:35:21 +1200 Subject: [PATCH 074/376] downgradedatabase: installing script Installing downgrade script so people don't need the source tree for it. Exception added in usage test because running the script without arguments is valid. (This avoids the need to knownfail it). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Aaron Haslett Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit 6dcf00ba0a470ba25aabae06b409ec95404c246f) --- python/samba/tests/usage.py | 2 ++ selftest/knownfail.d/usage | 1 - source4/scripting/bin/wscript_build | 3 ++- source4/scripting/wscript_build | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/python/samba/tests/usage.py b/python/samba/tests/usage.py index ba18a3e0729..4b7bccde758 100644 --- a/python/samba/tests/usage.py +++ b/python/samba/tests/usage.py @@ -78,6 +78,8 @@ EXCLUDE_USAGE = { 'selftest/tap2subunit', 'script/show_test_time', 'source4/scripting/bin/subunitrun', + 'bin/samba_downgrade_db', + 'source4/scripting/bin/samba_downgrade_db', 'source3/selftest/tests.py', 'selftest/tests.py', 'python/samba/subunit/run.py', diff --git a/selftest/knownfail.d/usage b/selftest/knownfail.d/usage index 0a495858e8c..3e54f80a2de 100644 --- a/selftest/knownfail.d/usage +++ b/selftest/knownfail.d/usage @@ -25,7 +25,6 @@ samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_rebuildextendedd samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_renamedc.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_repl_cleartext_pwd_py.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_rodcdns.none. -samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_samba_downgrade_db.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_samba_gpupdate.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_samba_gpupdate_.none. samba.tests.usage.samba.tests.usage.PythonScriptUsageTests.test_samba_kcc.none. diff --git a/source4/scripting/bin/wscript_build b/source4/scripting/bin/wscript_build index 42b37faa32a..87d23545487 100644 --- a/source4/scripting/bin/wscript_build +++ b/source4/scripting/bin/wscript_build @@ -7,6 +7,7 @@ if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'): 'samba_kcc', 'samba_upgradeprovision', 'samba_upgradedns', - 'gen_output.py']: + 'gen_output.py', + 'samba_downgrade_db']: bld.SAMBA_SCRIPT(script, pattern=script, installdir='.') bld.SAMBA_SCRIPT('samba-gpupdate', pattern='samba-gpupdate', installdir='.') diff --git a/source4/scripting/wscript_build b/source4/scripting/wscript_build index df24e921cd9..31c395d3e4b 100644 --- a/source4/scripting/wscript_build +++ b/source4/scripting/wscript_build @@ -4,7 +4,7 @@ from samba_utils import MODE_755 sbin_files = '' if bld.CONFIG_SET('AD_DC_BUILD_IS_ENABLED'): - sbin_files = 'bin/samba_dnsupdate bin/samba_spnupdate bin/samba_upgradedns bin/samba_kcc ' + sbin_files = 'bin/samba_downgrade_db bin/samba_dnsupdate bin/samba_spnupdate bin/samba_upgradedns bin/samba_kcc ' sbin_files += 'bin/samba-gpupdate' man_files = 'man/samba-gpupdate.8' -- 2.17.1 From 70726f2dfba3907ebc11b196aba61fe8358ac989 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Tue, 30 Jul 2019 16:40:55 +1200 Subject: [PATCH 075/376] ldb: Always log when the database pack format changes LDB_DEBUG_WARNING gets logged by Samba as level 2, whereas the default log level for Samba is 0. It's not really fair to the user to change the format of their database on disk and potentially not tell them. This patch adds a log with level zero (using a alias define, as this technically isn't a fatal problem). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit a2b0fc7c00360f37ed6819f21380294b70d4a195) --- lib/ldb/include/ldb.h | 3 +++ lib/ldb/ldb_key_value/ldb_kv_index.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/ldb/include/ldb.h b/lib/ldb/include/ldb.h index f06d5e95528..3cba0f4d543 100644 --- a/lib/ldb/include/ldb.h +++ b/lib/ldb/include/ldb.h @@ -220,6 +220,9 @@ struct tevent_context; enum ldb_debug_level {LDB_DEBUG_FATAL, LDB_DEBUG_ERROR, LDB_DEBUG_WARNING, LDB_DEBUG_TRACE}; +/* alias for something that's not a fatal error but we really want to log */ +#define LDB_DEBUG_ALWAYS_LOG LDB_DEBUG_FATAL + /** the user can optionally supply a debug function. The function is based on the vfprintf() style of interface, but with the addition diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c index ef275b28013..5de316579d7 100644 --- a/lib/ldb/ldb_key_value/ldb_kv_index.c +++ b/lib/ldb/ldb_key_value/ldb_kv_index.c @@ -3571,7 +3571,7 @@ static int re_pack(struct ldb_kv_private *ldb_kv, * want to spam the log. */ if ((!ctx->normal_record_seen) && (!ldb_dn_is_special(msg->dn))) { - ldb_debug(ldb, LDB_DEBUG_WARNING, + ldb_debug(ldb, LDB_DEBUG_ALWAYS_LOG, "Repacking database with format %#010x", ldb_kv->pack_format_version); ctx->normal_record_seen = true; -- 2.17.1 From b99fff86ebb64e31fd3577164f55246705511c3b Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Tue, 30 Jul 2019 15:02:25 +1200 Subject: [PATCH 076/376] ldb: Move where we update the pack format version Store it on the repack context so that we can log a more informative message "Repacking from format x to format y". While this is not really a big deal currently, it could be worth recording for potential future scenarios (i.e. supporting three or more pack versions), where upgrades could potentially skip an intermediary pack format version. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit d427bd6c775d8117504e76eed42cd2c383512e34) --- lib/ldb/ldb_key_value/ldb_kv.c | 2 -- lib/ldb/ldb_key_value/ldb_kv.h | 1 + lib/ldb/ldb_key_value/ldb_kv_index.c | 3 +++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ldb/ldb_key_value/ldb_kv.c b/lib/ldb/ldb_key_value/ldb_kv.c index f768fb5e1e4..4e7b8a116b3 100644 --- a/lib/ldb/ldb_key_value/ldb_kv.c +++ b/lib/ldb/ldb_key_value/ldb_kv.c @@ -315,8 +315,6 @@ static int ldb_kv_maybe_repack(struct ldb_kv_private *ldb_kv) { ldb_kv->target_pack_format_version) { int r; struct ldb_context *ldb = ldb_module_get_ctx(ldb_kv->module); - ldb_kv->pack_format_version = - ldb_kv->target_pack_format_version; r = ldb_kv_repack(ldb_kv->module); if (r != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_ERROR, diff --git a/lib/ldb/ldb_key_value/ldb_kv.h b/lib/ldb/ldb_key_value/ldb_kv.h index e627644ba34..f9dffae2dcf 100644 --- a/lib/ldb/ldb_key_value/ldb_kv.h +++ b/lib/ldb/ldb_key_value/ldb_kv.h @@ -175,6 +175,7 @@ struct ldb_kv_repack_context { int error; uint32_t count; bool normal_record_seen; + uint32_t old_version; }; diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c index 5de316579d7..eb84a790e00 100644 --- a/lib/ldb/ldb_key_value/ldb_kv_index.c +++ b/lib/ldb/ldb_key_value/ldb_kv_index.c @@ -3595,10 +3595,13 @@ int ldb_kv_repack(struct ldb_module *module) struct ldb_kv_repack_context ctx; int ret; + ctx.old_version = ldb_kv->pack_format_version; ctx.count = 0; ctx.error = LDB_SUCCESS; ctx.normal_record_seen = false; + ldb_kv->pack_format_version = ldb_kv->target_pack_format_version; + /* Iterate all database records and repack them in the new format */ ret = ldb_kv->kv_ops->iterate(ldb_kv, re_pack, &ctx); if (ret < 0) { -- 2.17.1 From 6de3d8f7ce0f97810515b81f4da1a7cc1eb4a241 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Tue, 30 Jul 2019 15:15:40 +1200 Subject: [PATCH 077/376] ldb: Change pack format defines to enum The main reason is so that any future pack formats will continue incrementing this number in a sequential fashion. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit 38e3e7cd328edac302e95ac8839e858c4a225485) --- lib/ldb/include/ldb_module.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/ldb/include/ldb_module.h b/lib/ldb/include/ldb_module.h index ab3d25c5c6e..8c1e5ee7936 100644 --- a/lib/ldb/include/ldb_module.h +++ b/lib/ldb/include/ldb_module.h @@ -559,12 +559,15 @@ int ldb_unpack_get_format(const struct ldb_val *data, #define LDB_UNPACK_DATA_FLAG_NO_ATTRS 0x0008 #define LDB_UNPACK_DATA_FLAG_READ_LOCKED 0x0010 -/* In-use packing formats */ -#define LDB_PACKING_FORMAT 0x26011967 -#define LDB_PACKING_FORMAT_V2 0x26011968 +enum ldb_pack_format { -/* Old packing formats */ -#define LDB_PACKING_FORMAT_NODN 0x26011966 + /* Old packing format (based on a somewhat arbitrary date) */ + LDB_PACKING_FORMAT_NODN = 0x26011966, + + /* In-use packing formats */ + LDB_PACKING_FORMAT, + LDB_PACKING_FORMAT_V2 +}; /** Forces a specific ldb handle to use the global event context. -- 2.17.1 From 1c2f1bd04abbedb3cfb31bb4a0ee4292c21dacc4 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Tue, 30 Jul 2019 16:40:55 +1200 Subject: [PATCH 078/376] ldb: Log pack format in user-friendly way The "format 0x26011968" log confused me (and I'm a developer). We can subtract the base offset from the pack format to get a more user-friendly number, e.g. v0 (not actually used), v1, v2, etc. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit 5fee9388422e259c2a56e4dccbf44d22ba426ca3) --- lib/ldb/ldb_key_value/ldb_kv_index.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c index eb84a790e00..27454d3f734 100644 --- a/lib/ldb/ldb_key_value/ldb_kv_index.c +++ b/lib/ldb/ldb_key_value/ldb_kv_index.c @@ -3526,6 +3526,18 @@ static int re_index(struct ldb_kv_private *ldb_kv, return 0; } +/* + * Convert the 4-byte pack format version to a number that's slightly + * more intelligible to a user e.g. version 0, 1, 2, etc. + */ +static uint32_t displayable_pack_version(uint32_t version) { + if (version < LDB_PACKING_FORMAT_NODN) { + return version; /* unknown - can't convert */ + } + + return (version - LDB_PACKING_FORMAT_NODN); +} + static int re_pack(struct ldb_kv_private *ldb_kv, _UNUSED_ struct ldb_val key, struct ldb_val val, @@ -3572,8 +3584,9 @@ static int re_pack(struct ldb_kv_private *ldb_kv, */ if ((!ctx->normal_record_seen) && (!ldb_dn_is_special(msg->dn))) { ldb_debug(ldb, LDB_DEBUG_ALWAYS_LOG, - "Repacking database with format %#010x", - ldb_kv->pack_format_version); + "Repacking database from v%u to v%u format", + displayable_pack_version(ctx->old_version), + displayable_pack_version(ldb_kv->pack_format_version)); ctx->normal_record_seen = true; } -- 2.17.1 From 18fb5fb911d098701e4af732977310e48ed403a9 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Wed, 31 Jul 2019 10:33:49 +1200 Subject: [PATCH 079/376] ldb: Log the partition we're repacking Firstly, with Samba AD this looks a little weird because we log the same message 5 times (once for every partition). If we log that we're doing this to records in different partitions, hopefully someone with a little Samba knowledge can figure out what's going on. Secondly, the info about what partitions are actually changing might be useful. E.g. if we hit a fatal error repacking the 3rd partition, and the transaction doesn't abort properly, then it would be useful to know what partitions were repacked and which ones weren't. There doesn't appear to be a useful name for the partition (ldb_kv->kv_ops->name() doesn't seem any more intelligible to a user), so just log the first record that we update. We can use that to infer the partition database). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit ee6537c29e747206ee607493ce15d4532fb670c8) --- lib/ldb/ldb_key_value/ldb_kv_index.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c index 27454d3f734..d955517ea10 100644 --- a/lib/ldb/ldb_key_value/ldb_kv_index.c +++ b/lib/ldb/ldb_key_value/ldb_kv_index.c @@ -3584,9 +3584,11 @@ static int re_pack(struct ldb_kv_private *ldb_kv, */ if ((!ctx->normal_record_seen) && (!ldb_dn_is_special(msg->dn))) { ldb_debug(ldb, LDB_DEBUG_ALWAYS_LOG, - "Repacking database from v%u to v%u format", + "Repacking database from v%u to v%u format " + "(first record %s)", displayable_pack_version(ctx->old_version), - displayable_pack_version(ldb_kv->pack_format_version)); + displayable_pack_version(ldb_kv->pack_format_version), + ldb_dn_get_linearized(msg->dn)); ctx->normal_record_seen = true; } -- 2.17.1 From d819a1c20503484b3624aeda426a37912a4ee692 Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Wed, 31 Jul 2019 10:54:29 +1200 Subject: [PATCH 080/376] ldb: Free memory when repacking database The msg for each database record is allocated on the module context, but never freed. The module seems like it could be a long-running context (as the database would normally get repacked by the samba executable). Even if it's not a proper leak, it shouldn't hurt to cleanup the memory. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam Autobuild-User(master): Garming Sam Autobuild-Date(master): Tue Aug 20 04:57:10 UTC 2019 on sn-devel-184 (cherry picked from commit b6516dbd24df8c78ed909c7ef9058b0844abb917) --- lib/ldb/ldb_key_value/ldb_kv_index.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/ldb/ldb_key_value/ldb_kv_index.c b/lib/ldb/ldb_key_value/ldb_kv_index.c index d955517ea10..0853b28fe40 100644 --- a/lib/ldb/ldb_key_value/ldb_kv_index.c +++ b/lib/ldb/ldb_key_value/ldb_kv_index.c @@ -3599,6 +3599,7 @@ static int re_pack(struct ldb_kv_private *ldb_kv, ctx->count); } + talloc_free(msg); return 0; } -- 2.17.1 From 80bd467affbda1d962f4deb3caa8a42c6531425d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 23 Aug 2019 12:02:05 +1200 Subject: [PATCH 081/376] ldb: Release ldb 2.0.6 * log database repack so users know what is happening BUG: https://bugzilla.samba.org/show_bug.cgi?id=14059 Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam --- lib/ldb/ABI/ldb-2.0.6.sigs | 283 ++++++++++++++++++++++++++++++ lib/ldb/ABI/pyldb-util-2.0.6.sigs | 2 + lib/ldb/wscript | 2 +- 3 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 lib/ldb/ABI/ldb-2.0.6.sigs create mode 100644 lib/ldb/ABI/pyldb-util-2.0.6.sigs diff --git a/lib/ldb/ABI/ldb-2.0.6.sigs b/lib/ldb/ABI/ldb-2.0.6.sigs new file mode 100644 index 00000000000..5049dc64ce1 --- /dev/null +++ b/lib/ldb/ABI/ldb-2.0.6.sigs @@ -0,0 +1,283 @@ +ldb_add: int (struct ldb_context *, const struct ldb_message *) +ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *) +ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...) +ldb_attr_casefold: char *(TALLOC_CTX *, const char *) +ldb_attr_dn: int (const char *) +ldb_attr_in_list: int (const char * const *, const char *) +ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *) +ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *) +ldb_base64_decode: int (char *) +ldb_base64_encode: char *(TALLOC_CTX *, const char *, int) +ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *) +ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val) +ldb_binary_encode_string: char *(TALLOC_CTX *, const char *) +ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t) +ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t) +ldb_check_critical_controls: int (struct ldb_control **) +ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *) +ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *) +ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **) +ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *) +ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *) +ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...) +ldb_debug_add: void (struct ldb_context *, const char *, ...) +ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level) +ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...) +ldb_delete: int (struct ldb_context *, struct ldb_dn *) +ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *) +ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...) +ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *) +ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...) +ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val) +ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *) +ldb_dn_check_special: bool (struct ldb_dn *, const char *) +ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *) +ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *) +ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val) +ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *) +ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *) +ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *) +ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *) +ldb_dn_get_casefold: const char *(struct ldb_dn *) +ldb_dn_get_comp_num: int (struct ldb_dn *) +ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int) +ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int) +ldb_dn_get_extended_comp_num: int (struct ldb_dn *) +ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *) +ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int) +ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *) +ldb_dn_get_linearized: const char *(struct ldb_dn *) +ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_get_rdn_name: const char *(struct ldb_dn *) +ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *) +ldb_dn_has_extended: bool (struct ldb_dn *) +ldb_dn_is_null: bool (struct ldb_dn *) +ldb_dn_is_special: bool (struct ldb_dn *) +ldb_dn_is_valid: bool (struct ldb_dn *) +ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) +ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) +ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) +ldb_dn_minimise: bool (struct ldb_dn *) +ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *) +ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...) +ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int) +ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int) +ldb_dn_remove_extended_components: void (struct ldb_dn *) +ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *) +ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val) +ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *) +ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *) +ldb_dn_validate: bool (struct ldb_dn *) +ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *) +ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int) +ldb_errstring: const char *(struct ldb_context *) +ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **) +ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *) +ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *) +ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *) +ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *) +ldb_get_create_perms: unsigned int (struct ldb_context *) +ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *) +ldb_get_event_context: struct tevent_context *(struct ldb_context *) +ldb_get_flags: unsigned int (struct ldb_context *) +ldb_get_opaque: void *(struct ldb_context *, const char *) +ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *) +ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *) +ldb_global_init: int (void) +ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *) +ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *) +ldb_handle_use_global_event_context: void (struct ldb_handle *) +ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *) +ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *) +ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *) +ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *) +ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *) +ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **) +ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *) +ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *) +ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *) +ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *) +ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **) +ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *) +ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *) +ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *) +ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *) +ldb_load_modules: int (struct ldb_context *, const char **) +ldb_map_add: int (struct ldb_module *, struct ldb_request *) +ldb_map_delete: int (struct ldb_module *, struct ldb_request *) +ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *) +ldb_map_modify: int (struct ldb_module *, struct ldb_request *) +ldb_map_rename: int (struct ldb_module *, struct ldb_request *) +ldb_map_search: int (struct ldb_module *, struct ldb_request *) +ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *) +ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope) +ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *) +ldb_match_msg_objectclass: int (const struct ldb_message *, const char *) +ldb_mod_register_control: int (struct ldb_module *, const char *) +ldb_modify: int (struct ldb_context *, const struct ldb_message *) +ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *) +ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *) +ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **) +ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int) +ldb_module_flags: uint32_t (struct ldb_context *) +ldb_module_get_ctx: struct ldb_context *(struct ldb_module *) +ldb_module_get_name: const char *(struct ldb_module *) +ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *) +ldb_module_get_private: void *(struct ldb_module *) +ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *) +ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **) +ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *) +ldb_module_next: struct ldb_module *(struct ldb_module *) +ldb_module_popt_options: struct poptOption **(struct ldb_context *) +ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **) +ldb_module_send_referral: int (struct ldb_request *, char *) +ldb_module_set_next: void (struct ldb_module *, struct ldb_module *) +ldb_module_set_private: void (struct ldb_module *, void *) +ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type) +ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *) +ldb_modules_load: int (const char *, const char *) +ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int) +ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **) +ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...) +ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *) +ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *) +ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *) +ldb_msg_add_string: int (struct ldb_message *, const char *, const char *) +ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **) +ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *) +ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *) +ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *) +ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *) +ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *) +ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *) +ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **) +ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *) +ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *) +ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *) +ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int) +ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *) +ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double) +ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int) +ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t) +ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *) +ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int) +ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t) +ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t) +ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t) +ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *) +ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *) +ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *) +ldb_msg_new: struct ldb_message *(TALLOC_CTX *) +ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **) +ldb_msg_remove_attr: void (struct ldb_message *, const char *) +ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *) +ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *) +ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *) +ldb_msg_sort_elements: void (struct ldb_message *) +ldb_next_del_trans: int (struct ldb_module *) +ldb_next_end_trans: int (struct ldb_module *) +ldb_next_init: int (struct ldb_module *) +ldb_next_prepare_commit: int (struct ldb_module *) +ldb_next_read_lock: int (struct ldb_module *) +ldb_next_read_unlock: int (struct ldb_module *) +ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *) +ldb_next_request: int (struct ldb_module *, struct ldb_request *) +ldb_next_start_trans: int (struct ldb_module *) +ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *) +ldb_options_copy: const char **(TALLOC_CTX *, const char **) +ldb_options_find: const char *(struct ldb_context *, const char **, const char *) +ldb_options_get: const char **(struct ldb_context *) +ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t) +ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *) +ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **) +ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *) +ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *) +ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *) +ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *) +ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t) +ldb_register_backend: int (const char *, ldb_connect_fn, bool) +ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *) +ldb_register_hook: int (ldb_hook_fn) +ldb_register_module: int (const struct ldb_module_ops *) +ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *) +ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *) +ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *) +ldb_req_get_custom_flags: uint32_t (struct ldb_request *) +ldb_req_is_untrusted: bool (struct ldb_request *) +ldb_req_location: const char *(struct ldb_request *) +ldb_req_mark_trusted: void (struct ldb_request *) +ldb_req_mark_untrusted: void (struct ldb_request *) +ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t) +ldb_req_set_location: void (struct ldb_request *, const char *) +ldb_request: int (struct ldb_context *, struct ldb_request *) +ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *) +ldb_request_done: int (struct ldb_request *, int) +ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *) +ldb_request_get_status: int (struct ldb_request *) +ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *) +ldb_request_set_state: void (struct ldb_request *, int) +ldb_reset_err_string: void (struct ldb_context *) +ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***) +ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *) +ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *) +ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *) +ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *) +ldb_schema_attribute_remove: void (struct ldb_context *, const char *) +ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int) +ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *) +ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *) +ldb_schema_set_override_indexlist: void (struct ldb_context *, bool) +ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...) +ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *) +ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *) +ldb_set_create_perms: void (struct ldb_context *, unsigned int) +ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *) +ldb_set_debug_stderr: int (struct ldb_context *) +ldb_set_default_dns: void (struct ldb_context *) +ldb_set_errstring: void (struct ldb_context *, const char *) +ldb_set_event_context: void (struct ldb_context *, struct tevent_context *) +ldb_set_flags: void (struct ldb_context *, unsigned int) +ldb_set_modules_dir: void (struct ldb_context *, const char *) +ldb_set_opaque: int (struct ldb_context *, const char *, void *) +ldb_set_require_private_event_context: void (struct ldb_context *) +ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int) +ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *) +ldb_set_utf8_default: void (struct ldb_context *) +ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t)) +ldb_setup_wellknown_attributes: int (struct ldb_context *) +ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *) +ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *) +ldb_strerror: const char *(int) +ldb_string_to_time: time_t (const char *) +ldb_string_utc_to_time: time_t (const char *) +ldb_timestring: char *(TALLOC_CTX *, time_t) +ldb_timestring_utc: char *(TALLOC_CTX *, time_t) +ldb_transaction_cancel: int (struct ldb_context *) +ldb_transaction_cancel_noerr: int (struct ldb_context *) +ldb_transaction_commit: int (struct ldb_context *) +ldb_transaction_prepare_commit: int (struct ldb_context *) +ldb_transaction_start: int (struct ldb_context *) +ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *) +ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int) +ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *) +ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *) +ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *) +ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *) +ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *) +ldb_val_string_cmp: int (const struct ldb_val *, const char *) +ldb_val_to_time: int (const struct ldb_val *, time_t *) +ldb_valid_attr_name: int (const char *) +ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list) +ldb_wait: int (struct ldb_handle *, enum ldb_wait_type) diff --git a/lib/ldb/ABI/pyldb-util-2.0.6.sigs b/lib/ldb/ABI/pyldb-util-2.0.6.sigs new file mode 100644 index 00000000000..74d6719d2bc --- /dev/null +++ b/lib/ldb/ABI/pyldb-util-2.0.6.sigs @@ -0,0 +1,2 @@ +pyldb_Dn_FromDn: PyObject *(struct ldb_dn *) +pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **) diff --git a/lib/ldb/wscript b/lib/ldb/wscript index 61f6b664902..a63a6c2171f 100644 --- a/lib/ldb/wscript +++ b/lib/ldb/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'ldb' -VERSION = '2.0.5' +VERSION = '2.0.6' import sys, os -- 2.17.1 From 756bea42e0c051580330680dd6350cefb102a21c Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 12 Aug 2019 16:11:13 +1000 Subject: [PATCH 082/376] ctdb-tools: Drop 'o' option from getopts command Commit 90de5e0594b9180226b9a13293afe31f18576b3d remove the processing for this option but forgot to remove it from the getopts command. Versions of ShellCheck >= 0.4.7 warn on this, so it is worth fixing. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14086 RN: Fix onnode test failure with ShellCheck >= 0.4.7 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 758962a0d435fa595e3917b860a8fd266d122550) --- ctdb/tools/onnode | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/tools/onnode b/ctdb/tools/onnode index e143ba2d4d4..d6595fff4aa 100755 --- a/ctdb/tools/onnode +++ b/ctdb/tools/onnode @@ -72,7 +72,7 @@ parse_options () { local opt - while getopts "cf:hno:pqvPi?" opt ; do + while getopts "cf:hnpqvPi?" opt ; do case "$opt" in c) current=true ;; f) ctdb_nodes_file="$OPTARG" ;; -- 2.17.1 From 900cc33accf07f5c80c941b7dc74e374185e2808 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 14 Aug 2019 10:06:00 +0200 Subject: [PATCH 083/376] vfs_default: use correct flag in vfswrap_fs_file_id Luckily using the wrong flag ST_EX_IFLAG_CALCULATED_ITIME currently results in the same semantics as using the correct ST_EX_IFLAG_CALCULATED_FILE_ID, as in vfs_default the non-calculated file_id is based a non-calculated itime. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14089 RN: vfs_default: use correct flag in vfswrap_fs_file_id Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 442a7c9ad8b020b2e88e41fea8a911d244023cb9) --- source3/modules/vfs_default.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 84c22bb1517..5095f65b746 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -2733,7 +2733,7 @@ static uint64_t vfswrap_fs_file_id(struct vfs_handle_struct *handle, { uint64_t file_id; - if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) { + if (!(psbuf->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) { return psbuf->st_ex_file_id; } -- 2.17.1 From 53f828969d0fde5cabd61e5a260a887c53fdc872 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 14 Aug 2019 10:11:15 +0200 Subject: [PATCH 084/376] vfs_glusterfs: initialize st_ex_file_id, st_ex_itime and st_ex_iflags BUG: https://bugzilla.samba.org/show_bug.cgi?id=14090 RN: vfs_glusterfs: initialize st_ex_file_id, st_ex_itime and st_ex_iflags Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Fri Aug 16 01:07:23 UTC 2019 on sn-devel-184 (cherry picked from commit 3ee78cc9979a72ebbe65a16c60967a1735a0d208) --- source3/modules/vfs_glusterfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index 95f32f9d0a6..56e03014fea 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -74,12 +74,16 @@ static void smb_stat_ex_from_stat(struct stat_ex *dst, const struct stat *src) dst->st_ex_btime.tv_sec = src->st_mtime; dst->st_ex_blksize = src->st_blksize; dst->st_ex_blocks = src->st_blocks; + dst->st_ex_file_id = dst->st_ex_ino; + dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_FILE_ID; #ifdef STAT_HAVE_NSEC dst->st_ex_atime.tv_nsec = src->st_atime_nsec; dst->st_ex_mtime.tv_nsec = src->st_mtime_nsec; dst->st_ex_ctime.tv_nsec = src->st_ctime_nsec; dst->st_ex_btime.tv_nsec = src->st_mtime_nsec; #endif + dst->st_ex_itime = dst->st_ex_btime; + dst->st_ex_iflags |= ST_EX_IFLAG_CALCULATED_ITIME; } /* pre-opened glfs_t */ -- 2.17.1 From c6d784debd8a9f9e576397a628de1e581aa7adbc Mon Sep 17 00:00:00 2001 From: Anoop C S Date: Mon, 5 Aug 2019 10:45:01 +0530 Subject: [PATCH 085/376] vfs_glusterfs: Enable profiling for file system operations BUG: https://bugzilla.samba.org/show_bug.cgi?id=14093 Signed-off-by: Anoop C S Reviewed-by: Guenther Deschner Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Tue Aug 20 19:25:28 UTC 2019 on sn-devel-184 Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Mon Aug 26 08:51:55 UTC 2019 on sn-devel-184 --- source3/modules/vfs_glusterfs.c | 337 +++++++++++++++++++++++++++----- 1 file changed, 288 insertions(+), 49 deletions(-) diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index 56e03014fea..483d28397f8 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -492,12 +492,16 @@ static DIR *vfs_gluster_opendir(struct vfs_handle_struct *handle, { glfs_fd_t *fd; + START_PROFILE(syscall_opendir); + fd = glfs_opendir(handle->data, smb_fname->base_name); if (fd == NULL) { DEBUG(0, ("glfs_opendir(%s) failed: %s\n", smb_fname->base_name, strerror(errno))); } + END_PROFILE(syscall_opendir); + return (DIR *) fd; } @@ -532,7 +536,13 @@ static DIR *vfs_gluster_fdopendir(struct vfs_handle_struct *handle, static int vfs_gluster_closedir(struct vfs_handle_struct *handle, DIR *dirp) { - return glfs_closedir((void *)dirp); + int ret; + + START_PROFILE(syscall_closedir); + ret = glfs_closedir((void *)dirp); + END_PROFILE(syscall_closedir); + + return ret; } static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle, @@ -543,6 +553,7 @@ static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle, struct stat stat; struct dirent *dirent = 0; + START_PROFILE(syscall_readdir); if (sbuf != NULL) { ret = glfs_readdirplus_r((void *)dirp, &stat, (void *)direntbuf, &dirent); @@ -551,6 +562,7 @@ static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle, } if ((ret < 0) || (dirent == NULL)) { + END_PROFILE(syscall_readdir); return NULL; } @@ -558,36 +570,59 @@ static struct dirent *vfs_gluster_readdir(struct vfs_handle_struct *handle, smb_stat_ex_from_stat(sbuf, &stat); } + END_PROFILE(syscall_readdir); return dirent; } static long vfs_gluster_telldir(struct vfs_handle_struct *handle, DIR *dirp) { - return glfs_telldir((void *)dirp); + long ret; + + START_PROFILE(syscall_telldir); + ret = glfs_telldir((void *)dirp); + END_PROFILE(syscall_telldir); + + return ret; } static void vfs_gluster_seekdir(struct vfs_handle_struct *handle, DIR *dirp, long offset) { + START_PROFILE(syscall_seekdir); glfs_seekdir((void *)dirp, offset); + END_PROFILE(syscall_seekdir); } static void vfs_gluster_rewinddir(struct vfs_handle_struct *handle, DIR *dirp) { + START_PROFILE(syscall_rewinddir); glfs_seekdir((void *)dirp, 0); + END_PROFILE(syscall_rewinddir); } static int vfs_gluster_mkdir(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, mode_t mode) { - return glfs_mkdir(handle->data, smb_fname->base_name, mode); + int ret; + + START_PROFILE(syscall_mkdir); + ret = glfs_mkdir(handle->data, smb_fname->base_name, mode); + END_PROFILE(syscall_mkdir); + + return ret; } static int vfs_gluster_rmdir(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { - return glfs_rmdir(handle->data, smb_fname->base_name); + int ret; + + START_PROFILE(syscall_rmdir); + ret = glfs_rmdir(handle->data, smb_fname->base_name); + END_PROFILE(syscall_rmdir); + + return ret; } static int vfs_gluster_open(struct vfs_handle_struct *handle, @@ -597,8 +632,11 @@ static int vfs_gluster_open(struct vfs_handle_struct *handle, glfs_fd_t *glfd; glfs_fd_t **p_tmp; + START_PROFILE(syscall_open); + p_tmp = VFS_ADD_FSP_EXTENSION(handle, fsp, glfs_fd_t *, NULL); if (p_tmp == NULL) { + END_PROFILE(syscall_open); errno = ENOMEM; return -1; } @@ -613,12 +651,15 @@ static int vfs_gluster_open(struct vfs_handle_struct *handle, } if (glfd == NULL) { + END_PROFILE(syscall_open); /* no extension destroy_fn, so no need to save errno */ VFS_REMOVE_FSP_EXTENSION(handle, fsp); return -1; } *p_tmp = glfd; + + END_PROFILE(syscall_open); /* An arbitrary value for error reporting, so you know its us. */ return 13371337; } @@ -626,31 +667,50 @@ static int vfs_gluster_open(struct vfs_handle_struct *handle, static int vfs_gluster_close(struct vfs_handle_struct *handle, files_struct *fsp) { - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + int ret; + glfs_fd_t *glfd = NULL; + + START_PROFILE(syscall_close); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE(syscall_close); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } VFS_REMOVE_FSP_EXTENSION(handle, fsp); - return glfs_close(glfd); + + ret = glfs_close(glfd); + END_PROFILE(syscall_close); + + return ret; } static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n, off_t offset) { - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + ssize_t ret; + glfs_fd_t *glfd = NULL; + + START_PROFILE_BYTES(syscall_pread, n); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE_BYTES(syscall_pread); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } #ifdef HAVE_GFAPI_VER_7_6 - return glfs_pread(glfd, data, n, offset, 0, NULL); + ret = glfs_pread(glfd, data, n, offset, 0, NULL); #else - return glfs_pread(glfd, data, n, offset, 0); + ret = glfs_pread(glfd, data, n, offset, 0); #endif + END_PROFILE_BYTES(syscall_pread); + + return ret; } struct glusterfs_aio_state; @@ -665,6 +725,7 @@ struct glusterfs_aio_state { bool cancelled; struct vfs_aio_state vfs_aio_state; struct timespec start; + SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes); }; static int aio_wrapper_destructor(struct glusterfs_aio_wrapper *wrap) @@ -706,6 +767,8 @@ static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data) } state->vfs_aio_state.duration = nsec_time_diff(&end, &state->start); + SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes); + /* * Write the state pointer to glusterfs_aio_state to the * pipe, so we can call tevent_req_done() from the main thread, @@ -878,6 +941,8 @@ static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct */ tevent_req_defer_callback(req, ev); + SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p, + state->profile_bytes, n); PROFILE_TIMESTAMP(&state->start); ret = glfs_pread_async(glfd, data, n, offset, 0, aio_glusterfs_done, state); @@ -927,6 +992,8 @@ static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct */ tevent_req_defer_callback(req, ev); + SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p, + state->profile_bytes, n); PROFILE_TIMESTAMP(&state->start); ret = glfs_pwrite_async(glfd, data, n, offset, 0, aio_glusterfs_done, state); @@ -972,29 +1039,47 @@ static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle, files_struct *fsp, const void *data, size_t n, off_t offset) { - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + ssize_t ret; + glfs_fd_t *glfd = NULL; + + START_PROFILE_BYTES(syscall_pwrite, n); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE_BYTES(syscall_pwrite); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } #ifdef HAVE_GFAPI_VER_7_6 - return glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL); + ret = glfs_pwrite(glfd, data, n, offset, 0, NULL, NULL); #else - return glfs_pwrite(glfd, data, n, offset, 0); + ret = glfs_pwrite(glfd, data, n, offset, 0); #endif + END_PROFILE_BYTES(syscall_pwrite); + + return ret; } static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset, int whence) { - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + off_t ret = 0; + glfs_fd_t *glfd = NULL; + + START_PROFILE(syscall_lseek); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE(syscall_lseek); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } - return glfs_lseek(glfd, offset, whence); + ret = glfs_lseek(glfd, offset, whence); + END_PROFILE(syscall_lseek); + + return ret; } static ssize_t vfs_gluster_sendfile(struct vfs_handle_struct *handle, int tofd, @@ -1018,8 +1103,14 @@ static int vfs_gluster_rename(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname_src, const struct smb_filename *smb_fname_dst) { - return glfs_rename(handle->data, smb_fname_src->base_name, - smb_fname_dst->base_name); + int ret; + + START_PROFILE(syscall_rename); + ret = glfs_rename(handle->data, smb_fname_src->base_name, + smb_fname_dst->base_name); + END_PROFILE(syscall_rename); + + return ret; } static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct @@ -1058,6 +1149,8 @@ static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct */ tevent_req_defer_callback(req, ev); + SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p, + state->profile_bytes, 0); PROFILE_TIMESTAMP(&state->start); ret = glfs_fsync_async(glfd, aio_glusterfs_done, state); if (ret < 0) { @@ -1082,6 +1175,7 @@ static int vfs_gluster_stat(struct vfs_handle_struct *handle, struct stat st; int ret; + START_PROFILE(syscall_stat); ret = glfs_stat(handle->data, smb_fname->base_name, &st); if (ret == 0) { smb_stat_ex_from_stat(&smb_fname->st, &st); @@ -1090,6 +1184,8 @@ static int vfs_gluster_stat(struct vfs_handle_struct *handle, DEBUG(0, ("glfs_stat(%s) failed: %s\n", smb_fname->base_name, strerror(errno))); } + END_PROFILE(syscall_stat); + return ret; } @@ -1098,9 +1194,13 @@ static int vfs_gluster_fstat(struct vfs_handle_struct *handle, { struct stat st; int ret; - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + glfs_fd_t *glfd = NULL; + + START_PROFILE(syscall_fstat); + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE(syscall_fstat); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } @@ -1113,6 +1213,8 @@ static int vfs_gluster_fstat(struct vfs_handle_struct *handle, DEBUG(0, ("glfs_fstat(%d) failed: %s\n", fsp->fh->fd, strerror(errno))); } + END_PROFILE(syscall_fstat); + return ret; } @@ -1122,6 +1224,7 @@ static int vfs_gluster_lstat(struct vfs_handle_struct *handle, struct stat st; int ret; + START_PROFILE(syscall_lstat); ret = glfs_lstat(handle->data, smb_fname->base_name, &st); if (ret == 0) { smb_stat_ex_from_stat(&smb_fname->st, &st); @@ -1130,6 +1233,8 @@ static int vfs_gluster_lstat(struct vfs_handle_struct *handle, DEBUG(0, ("glfs_lstat(%s) failed: %s\n", smb_fname->base_name, strerror(errno))); } + END_PROFILE(syscall_lstat); + return ret; } @@ -1137,33 +1242,59 @@ static uint64_t vfs_gluster_get_alloc_size(struct vfs_handle_struct *handle, files_struct *fsp, const SMB_STRUCT_STAT *sbuf) { - return sbuf->st_ex_blocks * 512; + uint64_t ret; + + START_PROFILE(syscall_get_alloc_size); + ret = sbuf->st_ex_blocks * 512; + END_PROFILE(syscall_get_alloc_size); + + return ret; } static int vfs_gluster_unlink(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { - return glfs_unlink(handle->data, smb_fname->base_name); + int ret; + + START_PROFILE(syscall_unlink); + ret = glfs_unlink(handle->data, smb_fname->base_name); + END_PROFILE(syscall_unlink); + + return ret; } static int vfs_gluster_chmod(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, mode_t mode) { - return glfs_chmod(handle->data, smb_fname->base_name, mode); + int ret; + + START_PROFILE(syscall_chmod); + ret = glfs_chmod(handle->data, smb_fname->base_name, mode); + END_PROFILE(syscall_chmod); + + return ret; } static int vfs_gluster_fchmod(struct vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + int ret; + glfs_fd_t *glfd = NULL; + START_PROFILE(syscall_fchmod); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE(syscall_fchmod); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } - return glfs_fchmod(glfd, mode); + ret = glfs_fchmod(glfd, mode); + END_PROFILE(syscall_fchmod); + + return ret; } static int vfs_gluster_chown(struct vfs_handle_struct *handle, @@ -1171,19 +1302,34 @@ static int vfs_gluster_chown(struct vfs_handle_struct *handle, uid_t uid, gid_t gid) { - return glfs_chown(handle->data, smb_fname->base_name, uid, gid); + int ret; + + START_PROFILE(syscall_chown); + ret = glfs_chown(handle->data, smb_fname->base_name, uid, gid); + END_PROFILE(syscall_chown); + + return ret; } static int vfs_gluster_fchown(struct vfs_handle_struct *handle, files_struct *fsp, uid_t uid, gid_t gid) { - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + int ret; + glfs_fd_t *glfd = NULL; + + START_PROFILE(syscall_fchown); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE(syscall_fchown); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } - return glfs_fchown(glfd, uid, gid); + ret = glfs_fchown(glfd, uid, gid); + END_PROFILE(syscall_fchown); + + return ret; } static int vfs_gluster_lchown(struct vfs_handle_struct *handle, @@ -1191,13 +1337,25 @@ static int vfs_gluster_lchown(struct vfs_handle_struct *handle, uid_t uid, gid_t gid) { - return glfs_lchown(handle->data, smb_fname->base_name, uid, gid); + int ret; + + START_PROFILE(syscall_lchown); + ret = glfs_lchown(handle->data, smb_fname->base_name, uid, gid); + END_PROFILE(syscall_lchown); + + return ret; } static int vfs_gluster_chdir(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { - return glfs_chdir(handle->data, smb_fname->base_name); + int ret; + + START_PROFILE(syscall_chdir); + ret = glfs_chdir(handle->data, smb_fname->base_name); + END_PROFILE(syscall_chdir); + + return ret; } static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle, @@ -1207,12 +1365,17 @@ static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle, char *ret; struct smb_filename *smb_fname = NULL; + START_PROFILE(syscall_getwd); + cwd = SMB_CALLOC_ARRAY(char, PATH_MAX); if (cwd == NULL) { + END_PROFILE(syscall_getwd); return NULL; } ret = glfs_getcwd(handle->data, cwd, PATH_MAX - 1); + END_PROFILE(syscall_getwd); + if (ret == NULL) { SAFE_FREE(cwd); return NULL; @@ -1230,8 +1393,11 @@ static int vfs_gluster_ntimes(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, struct smb_file_time *ft) { + int ret = -1; struct timespec times[2]; + START_PROFILE(syscall_ntimes); + if (null_timespec(ft->atime)) { times[0].tv_sec = smb_fname->st.st_ex_atime.tv_sec; times[0].tv_nsec = smb_fname->st.st_ex_atime.tv_nsec; @@ -1252,26 +1418,39 @@ static int vfs_gluster_ntimes(struct vfs_handle_struct *handle, &smb_fname->st.st_ex_atime) == 0) && (timespec_compare(×[1], &smb_fname->st.st_ex_mtime) == 0)) { + END_PROFILE(syscall_ntimes); return 0; } - return glfs_utimens(handle->data, smb_fname->base_name, times); + ret = glfs_utimens(handle->data, smb_fname->base_name, times); + END_PROFILE(syscall_ntimes); + + return ret; } static int vfs_gluster_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t offset) { - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + int ret; + glfs_fd_t *glfd = NULL; + + START_PROFILE(syscall_ftruncate); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE(syscall_ftruncate); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } #ifdef HAVE_GFAPI_VER_7_6 - return glfs_ftruncate(glfd, offset, NULL, NULL); + ret = glfs_ftruncate(glfd, offset, NULL, NULL); #else - return glfs_ftruncate(glfd, offset); + ret = glfs_ftruncate(glfd, offset); #endif + END_PROFILE(syscall_ftruncate); + + return ret; } static int vfs_gluster_fallocate(struct vfs_handle_struct *handle, @@ -1279,10 +1458,16 @@ static int vfs_gluster_fallocate(struct vfs_handle_struct *handle, uint32_t mode, off_t offset, off_t len) { + int ret; #ifdef HAVE_GFAPI_VER_6 + glfs_fd_t *glfd = NULL; int keep_size, punch_hole; - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + + START_PROFILE(syscall_fallocate); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE(syscall_fallocate); DBG_ERR("Failed to fetch gluster fd\n"); return -1; } @@ -1292,19 +1477,22 @@ static int vfs_gluster_fallocate(struct vfs_handle_struct *handle, mode &= ~(VFS_FALLOCATE_FL_KEEP_SIZE|VFS_FALLOCATE_FL_PUNCH_HOLE); if (mode != 0) { + END_PROFILE(syscall_fallocate); errno = ENOTSUP; return -1; } if (punch_hole) { - return glfs_discard(glfd, offset, len); + ret = glfs_discard(glfd, offset, len); } - return glfs_fallocate(glfd, keep_size, offset, len); + ret = glfs_fallocate(glfd, keep_size, offset, len); + END_PROFILE(syscall_fallocate); #else errno = ENOTSUP; - return -1; + ret = -1; #endif + return ret; } static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle, @@ -1313,9 +1501,13 @@ static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handl { char *result = NULL; struct smb_filename *result_fname = NULL; - char *resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1); + char *resolved_path = NULL; + START_PROFILE(syscall_realpath); + + resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1); if (resolved_path == NULL) { + END_PROFILE(syscall_realpath); errno = ENOMEM; return NULL; } @@ -1328,6 +1520,8 @@ static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handl } SAFE_FREE(resolved_path); + END_PROFILE(syscall_realpath); + return result_fname; } @@ -1337,10 +1531,16 @@ static bool vfs_gluster_lock(struct vfs_handle_struct *handle, { struct flock flock = { 0, }; int ret; - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + glfs_fd_t *glfd = NULL; + bool ok = false; + + START_PROFILE(syscall_fcntl_lock); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { DBG_ERR("Failed to fetch gluster fd\n"); - return false; + ok = false; + goto out; } flock.l_type = type; @@ -1355,17 +1555,25 @@ static bool vfs_gluster_lock(struct vfs_handle_struct *handle, /* lock query, true if someone else has locked */ if ((ret != -1) && (flock.l_type != F_UNLCK) && - (flock.l_pid != 0) && (flock.l_pid != getpid())) - return true; + (flock.l_pid != 0) && (flock.l_pid != getpid())) { + ok = true; + goto out; + } /* not me */ - return false; + ok = false; + goto out; } if (ret == -1) { - return false; + ok = false; + goto out; } - return true; + ok = true; +out: + END_PROFILE(syscall_fcntl_lock); + + return ok; } static int vfs_gluster_kernel_flock(struct vfs_handle_struct *handle, @@ -1389,8 +1597,13 @@ static bool vfs_gluster_getlock(struct vfs_handle_struct *handle, { struct flock flock = { 0, }; int ret; - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + glfs_fd_t *glfd = NULL; + + START_PROFILE(syscall_fcntl_getlock); + + glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { + END_PROFILE(syscall_fcntl_getlock); DBG_ERR("Failed to fetch gluster fd\n"); return false; } @@ -1404,6 +1617,7 @@ static bool vfs_gluster_getlock(struct vfs_handle_struct *handle, ret = glfs_posix_lock(glfd, F_GETLK, &flock); if (ret == -1) { + END_PROFILE(syscall_fcntl_getlock); return false; } @@ -1411,6 +1625,7 @@ static bool vfs_gluster_getlock(struct vfs_handle_struct *handle, *poffset = flock.l_start; *pcount = flock.l_len; *ppid = flock.l_pid; + END_PROFILE(syscall_fcntl_getlock); return true; } @@ -1419,9 +1634,15 @@ static int vfs_gluster_symlink(struct vfs_handle_struct *handle, const char *link_target, const struct smb_filename *new_smb_fname) { - return glfs_symlink(handle->data, + int ret; + + START_PROFILE(syscall_symlink); + ret = glfs_symlink(handle->data, link_target, new_smb_fname->base_name); + END_PROFILE(syscall_symlink); + + return ret; } static int vfs_gluster_readlink(struct vfs_handle_struct *handle, @@ -1429,16 +1650,28 @@ static int vfs_gluster_readlink(struct vfs_handle_struct *handle, char *buf, size_t bufsiz) { - return glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz); + int ret; + + START_PROFILE(syscall_readlink); + ret = glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz); + END_PROFILE(syscall_readlink); + + return ret; } static int vfs_gluster_link(struct vfs_handle_struct *handle, const struct smb_filename *old_smb_fname, const struct smb_filename *new_smb_fname) { - return glfs_link(handle->data, + int ret; + + START_PROFILE(syscall_link); + ret = glfs_link(handle->data, old_smb_fname->base_name, new_smb_fname->base_name); + END_PROFILE(syscall_link); + + return ret; } static int vfs_gluster_mknod(struct vfs_handle_struct *handle, @@ -1446,7 +1679,13 @@ static int vfs_gluster_mknod(struct vfs_handle_struct *handle, mode_t mode, SMB_DEV_T dev) { - return glfs_mknod(handle->data, smb_fname->base_name, mode, dev); + int ret; + + START_PROFILE(syscall_mknod); + ret = glfs_mknod(handle->data, smb_fname->base_name, mode, dev); + END_PROFILE(syscall_mknod); + + return ret; } static int vfs_gluster_chflags(struct vfs_handle_struct *handle, @@ -1505,7 +1744,7 @@ static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle, size_t size) { return glfs_getxattr(handle->data, smb_fname->base_name, - name, value, size); + name, value, size); } static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle, -- 2.17.1 From d8ba147db50feeeedbeb738a2be24c28e3790a45 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Sat, 18 May 2019 11:28:54 +0200 Subject: [PATCH 086/376] vfs:glusterfs_fuse: ensure fileids are constant across nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of adding a new gluster-specific mode to the fileid module, this patches provides a fileid algorithm as part of the glusterfs_fuse vfs module. This can not be configured further, simply adding the glusterfs_fuse vfs module to the vfs objects configuration will enable the new fileid mode. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13972 Signed-off-by: Michael Adam Signed-off-by: Guenther Deschner Autobuild-User(master): Günther Deschner Autobuild-Date(master): Sat Jul 13 22:54:56 UTC 2019 on sn-devel-184 (cherry picked from commit 5522aa1a4c34ee1a1e81db73cf41594bb10bd989) --- docs-xml/manpages/vfs_glusterfs_fuse.8.xml | 8 + source3/modules/vfs_glusterfs_fuse.c | 193 ++++++++++++++++++++- 2 files changed, 200 insertions(+), 1 deletion(-) diff --git a/docs-xml/manpages/vfs_glusterfs_fuse.8.xml b/docs-xml/manpages/vfs_glusterfs_fuse.8.xml index b9f7f42c6f2..f2aa624353e 100644 --- a/docs-xml/manpages/vfs_glusterfs_fuse.8.xml +++ b/docs-xml/manpages/vfs_glusterfs_fuse.8.xml @@ -48,6 +48,14 @@ case of an exisiting filename. + + Furthermore, this module implements a substitute file-id + mechanism. The default file-id mechanism is not working + correctly for gluster fuse mount re-exports, so in order to + avoid data loss, users exporting gluster fuse mounts with + Samba should enable this module. + + This module can be combined with other modules, but it should be the last module in the vfs objects diff --git a/source3/modules/vfs_glusterfs_fuse.c b/source3/modules/vfs_glusterfs_fuse.c index 51515aa0df4..c621f9abf8e 100644 --- a/source3/modules/vfs_glusterfs_fuse.c +++ b/source3/modules/vfs_glusterfs_fuse.c @@ -59,10 +59,201 @@ static int vfs_gluster_fuse_get_real_filename(struct vfs_handle_struct *handle, return 0; } +struct device_mapping_entry { + SMB_DEV_T device; /* the local device, for reference */ + uint64_t mapped_device; /* the mapped device */ +}; + +struct vfs_glusterfs_fuse_handle_data { + unsigned num_mapped_devices; + struct device_mapping_entry *mapped_devices; +}; + +/* a 64 bit hash, based on the one in tdb, copied from vfs_fileied */ +static uint64_t vfs_glusterfs_fuse_uint64_hash(const uint8_t *s, size_t len) +{ + uint64_t value; /* Used to compute the hash value. */ + uint32_t i; /* Used to cycle through random values. */ + + /* Set the initial value from the key size. */ + for (value = 0x238F13AFLL * len, i=0; i < len; i++) + value = (value + (((uint64_t)s[i]) << (i*5 % 24))); + + return (1103515243LL * value + 12345LL); +} + +static void vfs_glusterfs_fuse_load_devices( + struct vfs_glusterfs_fuse_handle_data *data) +{ + FILE *f; + struct mntent *m; + + data->num_mapped_devices = 0; + TALLOC_FREE(data->mapped_devices); + + f = setmntent("/etc/mtab", "r"); + if (!f) { + return; + } + + while ((m = getmntent(f))) { + struct stat st; + char *p; + uint64_t mapped_device; + + if (stat(m->mnt_dir, &st) != 0) { + /* TODO: log? */ + continue; + } + + /* strip the host part off of the fsname */ + p = strrchr(m->mnt_fsname, ':'); + if (p == NULL) { + p = m->mnt_fsname; + } else { + /* TODO: consider the case of '' ? */ + p++; + } + + mapped_device = vfs_glusterfs_fuse_uint64_hash( + (const uint8_t *)p, + strlen(p)); + + data->mapped_devices = talloc_realloc(data, + data->mapped_devices, + struct device_mapping_entry, + data->num_mapped_devices + 1); + if (data->mapped_devices == NULL) { + goto nomem; + } + + data->mapped_devices[data->num_mapped_devices].device = + st.st_dev; + data->mapped_devices[data->num_mapped_devices].mapped_device = + mapped_device; + + data->num_mapped_devices++; + } + + endmntent(f); + return; + +nomem: + data->num_mapped_devices = 0; + TALLOC_FREE(data->mapped_devices); + + endmntent(f); + return; +} + +static int vfs_glusterfs_fuse_map_device_cached( + struct vfs_glusterfs_fuse_handle_data *data, + SMB_DEV_T device, + uint64_t *mapped_device) +{ + unsigned i; + + for (i = 0; i < data->num_mapped_devices; i++) { + if (data->mapped_devices[i].device == device) { + *mapped_device = data->mapped_devices[i].mapped_device; + return 0; + } + } + + return -1; +} + +static int vfs_glusterfs_fuse_map_device( + struct vfs_glusterfs_fuse_handle_data *data, + SMB_DEV_T device, + uint64_t *mapped_device) +{ + int ret; + + ret = vfs_glusterfs_fuse_map_device_cached(data, device, mapped_device); + if (ret == 0) { + return 0; + } + + vfs_glusterfs_fuse_load_devices(data); + + ret = vfs_glusterfs_fuse_map_device_cached(data, device, mapped_device); + + return ret; +} + +static struct file_id vfs_glusterfs_fuse_file_id_create( + struct vfs_handle_struct *handle, + const SMB_STRUCT_STAT *sbuf) +{ + struct vfs_glusterfs_fuse_handle_data *data; + struct file_id id; + uint64_t mapped_device; + int ret; + + ZERO_STRUCT(id); + + id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf); + + SMB_VFS_HANDLE_GET_DATA(handle, data, + struct vfs_glusterfs_fuse_handle_data, + return id); + + ret = vfs_glusterfs_fuse_map_device(data, sbuf->st_ex_dev, + &mapped_device); + if (ret == 0) { + id.devid = mapped_device; + } else { + DBG_WARNING("Failed to map device [%jx], falling back to " + "standard file_id [%jx]", + (uintmax_t)sbuf->st_ex_dev, + (uintmax_t)id.devid); + } + + DBG_DEBUG("Returning dev [%jx] inode [%jx]\n", + (uintmax_t)id.devid, (uintmax_t)id.inode); + + return id; +} + +static int vfs_glusterfs_fuse_connect(struct vfs_handle_struct *handle, + const char *service, const char *user) +{ + struct vfs_glusterfs_fuse_handle_data *data; + int ret = SMB_VFS_NEXT_CONNECT(handle, service, user); + + if (ret < 0) { + return ret; + } + + data = talloc_zero(handle->conn, struct vfs_glusterfs_fuse_handle_data); + if (data == NULL) { + DBG_ERR("talloc_zero() failed.\n"); + SMB_VFS_NEXT_DISCONNECT(handle); + return -1; + } + + /* + * Fill the cache in the tree connect, so that the first file/dir access + * has chances of being fast... + */ + vfs_glusterfs_fuse_load_devices(data); + + SMB_VFS_HANDLE_SET_DATA(handle, data, NULL, + struct vfs_glusterfs_fuse_handle_data, + return -1); + + DBG_DEBUG("vfs_glusterfs_fuse_connect(): connected to service[%s]\n", + service); + + return 0; +} + struct vfs_fn_pointers glusterfs_fuse_fns = { - /* File Operations */ + .connect_fn = vfs_glusterfs_fuse_connect, .get_real_filename_fn = vfs_gluster_fuse_get_real_filename, + .file_id_create_fn = vfs_glusterfs_fuse_file_id_create, }; static_decl_vfs; -- 2.17.1 From 53b0fd2216dfd93ae0379f48e712294137e9b5b6 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Thu, 1 Aug 2019 00:47:29 +0200 Subject: [PATCH 087/376] vfs:glusterfs_fuse: build only if we have setmntent() FreeBSD and other platforms that don't have setmntent() and friends can not compile this module. This patch lets changes the build to only compile this module if the setmntent() function is found. This is the a follow-up fix to the actual fix for bug #13972. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13972 Signed-off-by: Michael Adam Reviewed-by: Amitay Isaacs Autobuild-User(master): Amitay Isaacs Autobuild-Date(master): Thu Aug 1 09:49:04 UTC 2019 on sn-devel-184 (cherry picked from commit f258cfaa1d07af6ac6e996006f6e59955cfe34ce) --- source3/wscript | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source3/wscript b/source3/wscript index ff72a173a4b..4a3e75605e7 100644 --- a/source3/wscript +++ b/source3/wscript @@ -1713,7 +1713,6 @@ main() { vfs_media_harmony vfs_unityed_media vfs_fruit vfs_shell_snap vfs_commit vfs_worm vfs_crossrename vfs_linux_xfs_sgid vfs_time_audit vfs_offline vfs_virusfilter - vfs_glusterfs_fuse ''')) default_shared_modules.extend(TO_LIST('auth_script idmap_tdb2 idmap_script')) # these have broken dependencies @@ -1775,6 +1774,9 @@ main() { if conf.CONFIG_SET('HAVE_GLUSTERFS'): default_shared_modules.extend(TO_LIST('vfs_glusterfs')) + if conf.CONFIG_SET('HAVE_SETMNTENT'): + default_shared_modules.extend(TO_LIST('vfs_glusterfs_fuse')) + if conf.CONFIG_SET('HAVE_VXFS'): default_shared_modules.extend(TO_LIST('vfs_vxfs')) -- 2.17.1 From 0b4a99c22f5e72d2bc6e2770b070e964866db148 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Thu, 8 Aug 2019 16:20:44 +1000 Subject: [PATCH 088/376] ctdb-daemon: Add function ctdb_ip_to_node() This is the core logic from ctdb_ip_to_pnn(), so re-implement that that function using ctdb_ip_to_node(). Something similar (ctdb_ip_to_nodeid()) was recently removed in commit 010c1d77cd7e192b1fff39b7b91fccbdbbf4a786 because it wasn't required. Now there is a use case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14084 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 3acb8e9d1c854b577d6be282257269df83055d31) --- ctdb/include/ctdb_private.h | 2 ++ ctdb/server/ctdb_server.c | 24 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 2bcc7c94156..1e9619faddf 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -831,6 +831,8 @@ void ctdb_stop_recoverd(struct ctdb_context *ctdb); int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport); +struct ctdb_node *ctdb_ip_to_node(struct ctdb_context *ctdb, + const ctdb_sock_addr *nodeip); uint32_t ctdb_ip_to_pnn(struct ctdb_context *ctdb, const ctdb_sock_addr *nodeip); diff --git a/ctdb/server/ctdb_server.c b/ctdb/server/ctdb_server.c index dcd761a2961..9724d1fe0a8 100644 --- a/ctdb/server/ctdb_server.c +++ b/ctdb/server/ctdb_server.c @@ -45,9 +45,9 @@ int ctdb_set_transport(struct ctdb_context *ctdb, const char *transport) return 0; } -/* Return the PNN for nodeip, CTDB_UNKNOWN_PNN if nodeip is invalid */ -uint32_t ctdb_ip_to_pnn(struct ctdb_context *ctdb, - const ctdb_sock_addr *nodeip) +/* Return the node structure for nodeip, NULL if nodeip is invalid */ +struct ctdb_node *ctdb_ip_to_node(struct ctdb_context *ctdb, + const ctdb_sock_addr *nodeip) { unsigned int nodeid; @@ -56,11 +56,25 @@ uint32_t ctdb_ip_to_pnn(struct ctdb_context *ctdb, continue; } if (ctdb_same_ip(&ctdb->nodes[nodeid]->address, nodeip)) { - return ctdb->nodes[nodeid]->pnn; + return ctdb->nodes[nodeid]; } } - return CTDB_UNKNOWN_PNN; + return NULL; +} + +/* Return the PNN for nodeip, CTDB_UNKNOWN_PNN if nodeip is invalid */ +uint32_t ctdb_ip_to_pnn(struct ctdb_context *ctdb, + const ctdb_sock_addr *nodeip) +{ + struct ctdb_node *node; + + node = ctdb_ip_to_node(ctdb, nodeip); + if (node == NULL) { + return CTDB_UNKNOWN_PNN; + } + + return node->pnn; } /* Load a nodes list file into a nodes array */ -- 2.17.1 From 4cf26ff2ec350db6b3ad5fa08dea602b3b842baf Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Fri, 9 Aug 2019 15:06:34 +1000 Subject: [PATCH 089/376] ctdb-tcp: Rename fd -> out_fd in_fd is coming soon. Fix coding style violations in the affected and adjacent lines. Modernise some debug macros and make them more consistent (e.g. drop logging of errno when strerror(errno) is already logged. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14084 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit c06620169fc178ea6db2631f03edf008285d8cf2) --- ctdb/tcp/ctdb_tcp.h | 2 +- ctdb/tcp/tcp_connect.c | 97 +++++++++++++++++++++++++----------------- ctdb/tcp/tcp_init.c | 22 ++++++---- 3 files changed, 72 insertions(+), 49 deletions(-) diff --git a/ctdb/tcp/ctdb_tcp.h b/ctdb/tcp/ctdb_tcp.h index 0a998c94da4..acd343fb8f3 100644 --- a/ctdb/tcp/ctdb_tcp.h +++ b/ctdb/tcp/ctdb_tcp.h @@ -39,7 +39,7 @@ struct ctdb_incoming { state associated with one tcp node */ struct ctdb_tcp_node { - int fd; + int out_fd; struct ctdb_queue *out_queue; struct tevent_fd *connect_fde; struct tevent_timer *connect_te; diff --git a/ctdb/tcp/tcp_connect.c b/ctdb/tcp/tcp_connect.c index d757abdf26c..4253f3bef7c 100644 --- a/ctdb/tcp/tcp_connect.c +++ b/ctdb/tcp/tcp_connect.c @@ -50,9 +50,9 @@ void ctdb_tcp_stop_connection(struct ctdb_node *node) talloc_free(tnode->connect_fde); tnode->connect_fde = NULL; tnode->connect_te = NULL; - if (tnode->fd != -1) { - close(tnode->fd); - tnode->fd = -1; + if (tnode->out_fd != -1) { + close(tnode->out_fd); + tnode->out_fd = -1; } } @@ -93,12 +93,13 @@ static void ctdb_node_connect_write(struct tevent_context *ev, int error = 0; socklen_t len = sizeof(error); int one = 1; + int ret; talloc_free(tnode->connect_te); tnode->connect_te = NULL; - if (getsockopt(tnode->fd, SOL_SOCKET, SO_ERROR, &error, &len) != 0 || - error != 0) { + ret = getsockopt(tnode->out_fd, SOL_SOCKET, SO_ERROR, &error, &len); + if (ret != 0 || error != 0) { ctdb_tcp_stop_connection(node); tnode->connect_te = tevent_add_timer(ctdb->ev, tnode, timeval_current_ofs(1, 0), @@ -109,19 +110,28 @@ static void ctdb_node_connect_write(struct tevent_context *ev, talloc_free(tnode->connect_fde); tnode->connect_fde = NULL; - if (setsockopt(tnode->fd,IPPROTO_TCP,TCP_NODELAY,(char *)&one,sizeof(one)) == -1) { - DEBUG(DEBUG_WARNING, ("Failed to set TCP_NODELAY on fd - %s\n", - strerror(errno))); + ret = setsockopt(tnode->out_fd, + IPPROTO_TCP, + TCP_NODELAY, + (char *)&one, + sizeof(one)); + if (ret == -1) { + DBG_WARNING("Failed to set TCP_NODELAY on fd - %s\n", + strerror(errno)); } - if (setsockopt(tnode->fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(one)) == -1) { - DEBUG(DEBUG_WARNING, ("Failed to set KEEPALIVE on fd - %s\n", - strerror(errno))); + ret = setsockopt(tnode->out_fd, + SOL_SOCKET, + SO_KEEPALIVE,(char *)&one, + sizeof(one)); + if (ret == -1) { + DBG_WARNING("Failed to set KEEPALIVE on fd - %s\n", + strerror(errno)); } - ctdb_queue_set_fd(tnode->out_queue, tnode->fd); + ctdb_queue_set_fd(tnode->out_queue, tnode->out_fd); /* the queue subsystem now owns this fd */ - tnode->fd = -1; + tnode->out_fd = -1; /* tell the ctdb layer we are connected */ node->ctdb->upcalls->node_connected(node); @@ -149,26 +159,24 @@ void ctdb_tcp_node_connect(struct tevent_context *ev, struct tevent_timer *te, sock_out = node->address; - tnode->fd = socket(sock_out.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); - if (tnode->fd == -1) { - DEBUG(DEBUG_ERR, (__location__ " Failed to create socket\n")); + tnode->out_fd = socket(sock_out.sa.sa_family, SOCK_STREAM, IPPROTO_TCP); + if (tnode->out_fd == -1) { + DBG_ERR("Failed to create socket\n"); return; } - ret = set_blocking(tnode->fd, false); + ret = set_blocking(tnode->out_fd, false); if (ret != 0) { - DEBUG(DEBUG_ERR, - (__location__ - " failed to set socket non-blocking (%s)\n", - strerror(errno))); - close(tnode->fd); - tnode->fd = -1; + DBG_ERR("Failed to set socket non-blocking (%s)\n", + strerror(errno)); + close(tnode->out_fd); + tnode->out_fd = -1; return; } - set_close_on_exec(tnode->fd); + set_close_on_exec(tnode->out_fd); - DEBUG(DEBUG_DEBUG, (__location__ " Created TCP SOCKET FD:%d\n", tnode->fd)); + DBG_DEBUG("Created TCP SOCKET FD:%d\n", tnode->out_fd); /* Bind our side of the socketpair to the same address we use to listen * on incoming CTDB traffic. @@ -197,39 +205,48 @@ void ctdb_tcp_node_connect(struct tevent_context *ev, struct tevent_timer *te, default: DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n", sock_in.sa.sa_family)); - close(tnode->fd); - tnode->fd = -1; + close(tnode->out_fd); + tnode->out_fd = -1; return; } - if (bind(tnode->fd, (struct sockaddr *)&sock_in, sockin_size) == -1) { - DEBUG(DEBUG_ERR, (__location__ " Failed to bind socket %s(%d)\n", - strerror(errno), errno)); - close(tnode->fd); - tnode->fd = -1; + ret = bind(tnode->out_fd, (struct sockaddr *)&sock_in, sockin_size); + if (ret == -1) { + DBG_ERR("Failed to bind socket (%s)\n", strerror(errno)); + close(tnode->out_fd); + tnode->out_fd = -1; return; } - if (connect(tnode->fd, (struct sockaddr *)&sock_out, sockout_size) != 0 && - errno != EINPROGRESS) { + ret = connect(tnode->out_fd, + (struct sockaddr *)&sock_out, + sockout_size); + if (ret != 0 && errno != EINPROGRESS) { ctdb_tcp_stop_connection(node); - tnode->connect_te = tevent_add_timer(ctdb->ev, tnode, + tnode->connect_te = tevent_add_timer(ctdb->ev, + tnode, timeval_current_ofs(1, 0), - ctdb_tcp_node_connect, node); + ctdb_tcp_node_connect, + node); return; } /* non-blocking connect - wait for write event */ - tnode->connect_fde = tevent_add_fd(node->ctdb->ev, tnode, tnode->fd, + tnode->connect_fde = tevent_add_fd(node->ctdb->ev, + tnode, + tnode->out_fd, TEVENT_FD_WRITE|TEVENT_FD_READ, - ctdb_node_connect_write, node); + ctdb_node_connect_write, + node); /* don't give it long to connect - retry in one second. This ensures that we find a node is up quickly (tcp normally backs off a syn reply delay by quite a lot) */ - tnode->connect_te = tevent_add_timer(ctdb->ev, tnode, + tnode->connect_te = tevent_add_timer(ctdb->ev, + tnode, timeval_current_ofs(1, 0), - ctdb_tcp_node_connect, node); + ctdb_tcp_node_connect, + node); } /* diff --git a/ctdb/tcp/tcp_init.c b/ctdb/tcp/tcp_init.c index 87d628aba93..6b1299f32b5 100644 --- a/ctdb/tcp/tcp_init.c +++ b/ctdb/tcp/tcp_init.c @@ -38,16 +38,16 @@ static int tnode_destructor(struct ctdb_tcp_node *tnode) { // struct ctdb_node *node = talloc_find_parent_bytype(tnode, struct ctdb_node); - if (tnode->fd != -1) { - close(tnode->fd); - tnode->fd = -1; + if (tnode->out_fd != -1) { + close(tnode->out_fd); + tnode->out_fd = -1; } return 0; } /* - initialise tcp portion of a ctdb node + initialise tcp portion of a ctdb node */ static int ctdb_tcp_add_node(struct ctdb_node *node) { @@ -55,13 +55,19 @@ static int ctdb_tcp_add_node(struct ctdb_node *node) tnode = talloc_zero(node, struct ctdb_tcp_node); CTDB_NO_MEMORY(node->ctdb, tnode); - tnode->fd = -1; + tnode->out_fd = -1; node->private_data = tnode; talloc_set_destructor(tnode, tnode_destructor); - tnode->out_queue = ctdb_queue_setup(node->ctdb, node, tnode->fd, CTDB_TCP_ALIGNMENT, - ctdb_tcp_tnode_cb, node, "to-node-%s", node->name); - + tnode->out_queue = ctdb_queue_setup(node->ctdb, + node, + tnode->out_fd, + CTDB_TCP_ALIGNMENT, + ctdb_tcp_tnode_cb, + node, + "to-node-%s", + node->name); + return 0; } -- 2.17.1 From bf39d0cff16cd240ceddb3cb88183ad61e667ac2 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Fri, 9 Aug 2019 15:29:36 +1000 Subject: [PATCH 090/376] ctdb-tcp: Move incoming fd and queue into struct ctdb_tcp_node This makes it easy to track both incoming and outgoing connectivity states. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14084 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit c68b6f96f26664459187ab2fbd56767fb31767e0) --- ctdb/tcp/ctdb_tcp.h | 14 ++++----- ctdb/tcp/tcp_connect.c | 64 +++++++++++++++++++++++++++--------------- ctdb/tcp/tcp_init.c | 8 ++++++ ctdb/tcp/tcp_io.c | 9 ++++-- 4 files changed, 61 insertions(+), 34 deletions(-) diff --git a/ctdb/tcp/ctdb_tcp.h b/ctdb/tcp/ctdb_tcp.h index acd343fb8f3..9a615fc6393 100644 --- a/ctdb/tcp/ctdb_tcp.h +++ b/ctdb/tcp/ctdb_tcp.h @@ -26,23 +26,19 @@ struct ctdb_tcp { int listen_fd; }; -/* - state associated with an incoming connection -*/ -struct ctdb_incoming { - struct ctdb_context *ctdb; - int fd; - struct ctdb_queue *queue; -}; - /* state associated with one tcp node */ struct ctdb_tcp_node { int out_fd; struct ctdb_queue *out_queue; + struct tevent_fd *connect_fde; struct tevent_timer *connect_te; + + struct ctdb_context *ctdb; + int in_fd; + struct ctdb_queue *in_queue; }; diff --git a/ctdb/tcp/tcp_connect.c b/ctdb/tcp/tcp_connect.c index 4253f3bef7c..866454f3d29 100644 --- a/ctdb/tcp/tcp_connect.c +++ b/ctdb/tcp/tcp_connect.c @@ -262,8 +262,8 @@ static void ctdb_listen_event(struct tevent_context *ev, struct tevent_fd *fde, ctdb_sock_addr addr; socklen_t len; int fd; - uint32_t pnn; - struct ctdb_incoming *in; + struct ctdb_node *node; + struct ctdb_tcp_node *tnode; int one = 1; int ret; @@ -273,41 +273,61 @@ static void ctdb_listen_event(struct tevent_context *ev, struct tevent_fd *fde, if (fd == -1) return; smb_set_close_on_exec(fd); - pnn = ctdb_ip_to_pnn(ctdb, &addr); - - if (pnn == CTDB_UNKNOWN_PNN) { + node = ctdb_ip_to_node(ctdb, &addr); + if (node == NULL) { D_ERR("Refused connection from unknown node %s\n", ctdb_addr_to_str(&addr)); close(fd); return; } - in = talloc_zero(ctcp, struct ctdb_incoming); - in->fd = fd; - in->ctdb = ctdb; + tnode = talloc_get_type_abort(node->private_data, + struct ctdb_tcp_node); + if (tnode == NULL) { + /* This can't happen - see ctdb_tcp_initialise() */ + DBG_ERR("INTERNAL ERROR setting up connection from node %s\n", + ctdb_addr_to_str(&addr)); + close(fd); + return; + } - ret = set_blocking(in->fd, false); + ret = set_blocking(fd, false); if (ret != 0) { - DEBUG(DEBUG_ERR, - (__location__ - " failed to set socket non-blocking (%s)\n", - strerror(errno))); - close(in->fd); - in->fd = -1; + DBG_ERR("Failed to set socket non-blocking (%s)\n", + strerror(errno)); + close(fd); return; } - set_close_on_exec(in->fd); + set_close_on_exec(fd); - DEBUG(DEBUG_DEBUG, (__location__ " Created SOCKET FD:%d to incoming ctdb connection\n", fd)); + DBG_DEBUG("Created SOCKET FD:%d to incoming ctdb connection\n", fd); - if (setsockopt(in->fd,SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(one)) == -1) { - DEBUG(DEBUG_WARNING, ("Failed to set KEEPALIVE on fd - %s\n", - strerror(errno))); + ret = setsockopt(fd, + SOL_SOCKET, + SO_KEEPALIVE, + (char *)&one, + sizeof(one)); + if (ret == -1) { + DBG_WARNING("Failed to set KEEPALIVE on fd - %s\n", + strerror(errno)); + } + + tnode->in_queue = ctdb_queue_setup(ctdb, + tnode, + fd, + CTDB_TCP_ALIGNMENT, + ctdb_tcp_read_cb, + tnode, + "ctdbd-%s", + ctdb_addr_to_str(&addr)); + if (tnode->in_queue == NULL) { + DBG_ERR("Failed to set up incoming queue\n"); + close(fd); + return; } - in->queue = ctdb_queue_setup(ctdb, in, in->fd, CTDB_TCP_ALIGNMENT, - ctdb_tcp_read_cb, in, "ctdbd-%s", ctdb_addr_to_str(&addr)); + tnode->in_fd = fd; } diff --git a/ctdb/tcp/tcp_init.c b/ctdb/tcp/tcp_init.c index 6b1299f32b5..d4b42b0d0f2 100644 --- a/ctdb/tcp/tcp_init.c +++ b/ctdb/tcp/tcp_init.c @@ -43,6 +43,11 @@ static int tnode_destructor(struct ctdb_tcp_node *tnode) tnode->out_fd = -1; } + if (tnode->in_fd != -1) { + close(tnode->in_fd); + tnode->in_fd = -1; + } + return 0; } @@ -56,6 +61,9 @@ static int ctdb_tcp_add_node(struct ctdb_node *node) CTDB_NO_MEMORY(node->ctdb, tnode); tnode->out_fd = -1; + tnode->in_fd = -1; + tnode->ctdb = node->ctdb; + node->private_data = tnode; talloc_set_destructor(tnode, tnode_destructor); diff --git a/ctdb/tcp/tcp_io.c b/ctdb/tcp/tcp_io.c index 0eb8e25eea3..be4558b16ea 100644 --- a/ctdb/tcp/tcp_io.c +++ b/ctdb/tcp/tcp_io.c @@ -37,7 +37,8 @@ */ void ctdb_tcp_read_cb(uint8_t *data, size_t cnt, void *args) { - struct ctdb_incoming *in = talloc_get_type(args, struct ctdb_incoming); + struct ctdb_tcp_node *tnode = talloc_get_type_abort( + args, struct ctdb_tcp_node); struct ctdb_req_header *hdr = (struct ctdb_req_header *)data; if (data == NULL) { @@ -69,11 +70,13 @@ void ctdb_tcp_read_cb(uint8_t *data, size_t cnt, void *args) } /* tell the ctdb layer above that we have a packet */ - in->ctdb->upcalls->recv_pkt(in->ctdb, data, cnt); + tnode->ctdb->upcalls->recv_pkt(tnode->ctdb, data, cnt); return; failed: - TALLOC_FREE(in); + TALLOC_FREE(tnode->in_queue); + close(tnode->in_fd); + tnode->in_fd = -1; TALLOC_FREE(data); } -- 2.17.1 From 1ef2ffbab865b80c90a69b5899285c0b7409c26d Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Thu, 15 Aug 2019 15:45:16 +1000 Subject: [PATCH 091/376] ctdb-tcp: Use TALLOC_FREE() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14084 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit d80d9edb4dc107b15a35a39e5c966a3eaed6453a) --- ctdb/tcp/tcp_connect.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ctdb/tcp/tcp_connect.c b/ctdb/tcp/tcp_connect.c index 866454f3d29..16d75481050 100644 --- a/ctdb/tcp/tcp_connect.c +++ b/ctdb/tcp/tcp_connect.c @@ -46,10 +46,8 @@ void ctdb_tcp_stop_connection(struct ctdb_node *node) node->private_data, struct ctdb_tcp_node); ctdb_queue_set_fd(tnode->out_queue, -1); - talloc_free(tnode->connect_te); - talloc_free(tnode->connect_fde); - tnode->connect_fde = NULL; - tnode->connect_te = NULL; + TALLOC_FREE(tnode->connect_te); + TALLOC_FREE(tnode->connect_fde); if (tnode->out_fd != -1) { close(tnode->out_fd); tnode->out_fd = -1; -- 2.17.1 From 6668733c306896a779c707acdd9912efcf52c0da Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Thu, 15 Aug 2019 15:57:31 +1000 Subject: [PATCH 092/376] ctdb-tcp: Create outbound queue when the connection becomes writable Since commit ddd97553f0a8bfaada178ec4a7460d76fa21f079 ctdb_queue_send() doesn't queue a packet if the connection isn't yet established (i.e. when fd == -1). So, don't bother creating the outbound queue during initialisation but create it when the connection becomes writable. Now the presence of the queue indicates that the outbound connection is up. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14084 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 7f4854d9643a096a6d8a354fcd27b7c6ed24a75e) --- ctdb/tcp/tcp_connect.c | 23 ++++++++++++++++++++--- ctdb/tcp/tcp_init.c | 9 --------- ctdb/tcp/tcp_io.c | 5 +++++ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/ctdb/tcp/tcp_connect.c b/ctdb/tcp/tcp_connect.c index 16d75481050..4374242015c 100644 --- a/ctdb/tcp/tcp_connect.c +++ b/ctdb/tcp/tcp_connect.c @@ -44,8 +44,8 @@ void ctdb_tcp_stop_connection(struct ctdb_node *node) { struct ctdb_tcp_node *tnode = talloc_get_type( node->private_data, struct ctdb_tcp_node); - - ctdb_queue_set_fd(tnode->out_queue, -1); + + TALLOC_FREE(tnode->out_queue); TALLOC_FREE(tnode->connect_te); TALLOC_FREE(tnode->connect_fde); if (tnode->out_fd != -1) { @@ -126,7 +126,24 @@ static void ctdb_node_connect_write(struct tevent_context *ev, strerror(errno)); } - ctdb_queue_set_fd(tnode->out_queue, tnode->out_fd); + tnode->out_queue = ctdb_queue_setup(node->ctdb, + tnode, + tnode->out_fd, + CTDB_TCP_ALIGNMENT, + ctdb_tcp_tnode_cb, + node, + "to-node-%s", + node->name); + if (tnode->out_queue == NULL) { + DBG_ERR("Failed to set up outgoing queue\n"); + ctdb_tcp_stop_connection(node); + tnode->connect_te = tevent_add_timer(ctdb->ev, + tnode, + timeval_current_ofs(1, 0), + ctdb_tcp_node_connect, + node); + return; + } /* the queue subsystem now owns this fd */ tnode->out_fd = -1; diff --git a/ctdb/tcp/tcp_init.c b/ctdb/tcp/tcp_init.c index d4b42b0d0f2..a9cb9b36a01 100644 --- a/ctdb/tcp/tcp_init.c +++ b/ctdb/tcp/tcp_init.c @@ -67,15 +67,6 @@ static int ctdb_tcp_add_node(struct ctdb_node *node) node->private_data = tnode; talloc_set_destructor(tnode, tnode_destructor); - tnode->out_queue = ctdb_queue_setup(node->ctdb, - node, - tnode->out_fd, - CTDB_TCP_ALIGNMENT, - ctdb_tcp_tnode_cb, - node, - "to-node-%s", - node->name); - return 0; } diff --git a/ctdb/tcp/tcp_io.c b/ctdb/tcp/tcp_io.c index be4558b16ea..e33ed44048e 100644 --- a/ctdb/tcp/tcp_io.c +++ b/ctdb/tcp/tcp_io.c @@ -87,5 +87,10 @@ int ctdb_tcp_queue_pkt(struct ctdb_node *node, uint8_t *data, uint32_t length) { struct ctdb_tcp_node *tnode = talloc_get_type(node->private_data, struct ctdb_tcp_node); + if (tnode->out_queue == NULL) { + DBG_DEBUG("No outgoing connection, dropping packet\n"); + return 0; + } + return ctdb_queue_send(tnode->out_queue, data, length); } -- 2.17.1 From adb19f17cd1a778a6ee58d7f4658b9f27ea087de Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Fri, 9 Aug 2019 15:33:05 +1000 Subject: [PATCH 093/376] ctdb-tcp: Only mark a node connected if both directions are up Nodes are currently marked as up if the outgoing connection is established. However, if the incoming connection is not yet established then this node could send a request where the replying node can not queue its reply. Wait until both directions are up before marking a node as connected. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14084 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 8c98c10f242bc722beffc711e85c0e4f2e74cd57) --- ctdb/tcp/tcp_connect.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ctdb/tcp/tcp_connect.c b/ctdb/tcp/tcp_connect.c index 4374242015c..fd635b9abf2 100644 --- a/ctdb/tcp/tcp_connect.c +++ b/ctdb/tcp/tcp_connect.c @@ -148,8 +148,14 @@ static void ctdb_node_connect_write(struct tevent_context *ev, /* the queue subsystem now owns this fd */ tnode->out_fd = -1; - /* tell the ctdb layer we are connected */ - node->ctdb->upcalls->node_connected(node); + /* + * Mark the node to which this connection has been established + * as connected, but only if the corresponding listening + * socket is also connected + */ + if (tnode->in_fd != -1) { + node->ctdb->upcalls->node_connected(node); + } } @@ -343,7 +349,15 @@ static void ctdb_listen_event(struct tevent_context *ev, struct tevent_fd *fde, } tnode->in_fd = fd; -} + + /* + * Mark the connecting node as connected, but only if the + * corresponding outbound connected is also up + */ + if (tnode->out_queue != NULL) { + node->ctdb->upcalls->node_connected(node); + } + } /* -- 2.17.1 From 240ad91944d617d33b85aaeeed2a57ecf1ce9c67 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Tue, 13 Aug 2019 17:08:43 +1000 Subject: [PATCH 094/376] ctdb-tcp: Mark node as disconnected if incoming connection goes away To make it easy to pass the node data to the upcall, the private data for ctdb_tcp_read_cb() needs to be changed from tnode to node. RN: Avoid marking a node as connected before it can receive packets BUG: https://bugzilla.samba.org/show_bug.cgi?id=14084 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs Autobuild-User(master): Martin Schwenke Autobuild-Date(master): Fri Aug 16 22:50:35 UTC 2019 on sn-devel-184 (cherry picked from commit 73c850eda4209b688a169aeeb20c453b738cbb35) --- ctdb/tcp/tcp_connect.c | 2 +- ctdb/tcp/tcp_io.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ctdb/tcp/tcp_connect.c b/ctdb/tcp/tcp_connect.c index fd635b9abf2..6123380ca9f 100644 --- a/ctdb/tcp/tcp_connect.c +++ b/ctdb/tcp/tcp_connect.c @@ -339,7 +339,7 @@ static void ctdb_listen_event(struct tevent_context *ev, struct tevent_fd *fde, fd, CTDB_TCP_ALIGNMENT, ctdb_tcp_read_cb, - tnode, + node, "ctdbd-%s", ctdb_addr_to_str(&addr)); if (tnode->in_queue == NULL) { diff --git a/ctdb/tcp/tcp_io.c b/ctdb/tcp/tcp_io.c index e33ed44048e..e8ebff887e1 100644 --- a/ctdb/tcp/tcp_io.c +++ b/ctdb/tcp/tcp_io.c @@ -37,8 +37,9 @@ */ void ctdb_tcp_read_cb(uint8_t *data, size_t cnt, void *args) { + struct ctdb_node *node = talloc_get_type_abort(args, struct ctdb_node); struct ctdb_tcp_node *tnode = talloc_get_type_abort( - args, struct ctdb_tcp_node); + node->private_data, struct ctdb_tcp_node); struct ctdb_req_header *hdr = (struct ctdb_req_header *)data; if (data == NULL) { @@ -77,6 +78,8 @@ failed: TALLOC_FREE(tnode->in_queue); close(tnode->in_fd); tnode->in_fd = -1; + node->ctdb->upcalls->node_dead(node); + TALLOC_FREE(data); } -- 2.17.1 From 093973899580c2fd1a95d067ff695388b7bdc4f8 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 19 Aug 2019 21:47:03 +1000 Subject: [PATCH 095/376] ctdb-daemon: Factor out new function ctdb_node_become_inactive() This is a superset of ctdb_local_node_got_banned() so will replace that function, and will also be used in the NODE_STOP control. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14087 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit a42bcaabb63722411bee52b80cbfc795593defbc) --- ctdb/include/ctdb_private.h | 2 ++ ctdb/server/ctdb_recover.c | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 1e9619faddf..d9d13fad358 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -819,6 +819,8 @@ int32_t ctdb_control_recd_ping(struct ctdb_context *ctdb); int32_t ctdb_control_set_recmaster(struct ctdb_context *ctdb, uint32_t opcode, TDB_DATA indata); +void ctdb_node_become_inactive(struct ctdb_context *ctdb); + int32_t ctdb_control_stop_node(struct ctdb_context *ctdb); int32_t ctdb_control_continue_node(struct ctdb_context *ctdb); diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c index 343728839c1..df60a4cb9c0 100644 --- a/ctdb/server/ctdb_recover.c +++ b/ctdb/server/ctdb_recover.c @@ -1420,6 +1420,49 @@ int32_t ctdb_control_set_recmaster(struct ctdb_context *ctdb, uint32_t opcode, T return 0; } +void ctdb_node_become_inactive(struct ctdb_context *ctdb) +{ + struct ctdb_db_context *ctdb_db; + + D_WARNING("Making node INACTIVE\n"); + + /* + * Do not service database calls - reset generation to invalid + * so this node ignores any REQ/REPLY CALL/DMASTER + */ + ctdb->vnn_map->generation = INVALID_GENERATION; + for (ctdb_db = ctdb->db_list; ctdb_db != NULL; ctdb_db = ctdb_db->next) { + ctdb_db->generation = INVALID_GENERATION; + } + + /* + * Although this bypasses the control, the only thing missing + * is the deferred drop of all public IPs, which isn't + * necessary because they are dropped below + */ + if (ctdb->recovery_mode != CTDB_RECOVERY_ACTIVE) { + D_NOTICE("Recovery mode set to ACTIVE\n"); + ctdb->recovery_mode = CTDB_RECOVERY_ACTIVE; + } + + /* + * Initiate database freeze - this will be scheduled for + * immediate execution and will be in progress long before the + * calling control returns + */ + ctdb_daemon_send_control(ctdb, + ctdb->pnn, + 0, + CTDB_CONTROL_FREEZE, + 0, + CTDB_CTRL_FLAG_NOREPLY, + tdb_null, + NULL, + NULL); + + D_NOTICE("Dropping all public IP addresses\n"); + ctdb_release_all_ips(ctdb); +} int32_t ctdb_control_stop_node(struct ctdb_context *ctdb) { -- 2.17.1 From a93c591a11a9b19f4f5df87c76e3b2f3f7404339 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 19 Aug 2019 21:52:57 +1000 Subject: [PATCH 096/376] ctdb-daemon: Switch banning code to use ctdb_node_become_inactive() There's no reason to avoid immediately setting recovery mode to active and initiating freeze of databases. This effectively reverts the following commits: d8f3b490bbb691c9916eed0df5b980c1aef23c85 b4357a79d916b1f8ade8fa78563fbef0ce670aa9 The latter is now implemented using a control, resulting in looser coupling. See also the following commit: f8141e91a693912ea1107a49320e83702a80757a BUG: https://bugzilla.samba.org/show_bug.cgi?id=14087 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 0f5f7b7cf4e970f3f36c5e0b3d09e710fe90801a) --- ctdb/server/ctdb_banning.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_banning.c b/ctdb/server/ctdb_banning.c index 9cd163645a1..11794dc5b0b 100644 --- a/ctdb/server/ctdb_banning.c +++ b/ctdb/server/ctdb_banning.c @@ -129,7 +129,7 @@ int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata) ctdb_ban_node_event, ctdb); if (!already_banned) { - ctdb_local_node_got_banned(ctdb); + ctdb_node_become_inactive(ctdb); } return 0; } -- 2.17.1 From f454db8d960bce78e492cdec344257a2ee094514 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Tue, 20 Aug 2019 11:29:42 +1000 Subject: [PATCH 097/376] ctdb-daemon: Drop unused function ctdb_local_node_got_banned() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14087 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 91ac4c13d8472955d1f04bd775ec4b3ff8bf1b61) --- ctdb/include/ctdb_private.h | 1 - ctdb/server/ctdb_banning.c | 24 ------------------------ 2 files changed, 25 deletions(-) diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index d9d13fad358..1f168dae2b8 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -481,7 +481,6 @@ int ctdb_ibw_init(struct ctdb_context *ctdb); /* from ctdb_banning.c */ -void ctdb_local_node_got_banned(struct ctdb_context *ctdb); int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata); int32_t ctdb_control_get_ban_state(struct ctdb_context *ctdb, TDB_DATA *outdata); void ctdb_ban_self(struct ctdb_context *ctdb); diff --git a/ctdb/server/ctdb_banning.c b/ctdb/server/ctdb_banning.c index 11794dc5b0b..3c711575e8c 100644 --- a/ctdb/server/ctdb_banning.c +++ b/ctdb/server/ctdb_banning.c @@ -57,30 +57,6 @@ static void ctdb_ban_node_event(struct tevent_context *ev, } } -void ctdb_local_node_got_banned(struct ctdb_context *ctdb) -{ - struct ctdb_db_context *ctdb_db; - - DEBUG(DEBUG_NOTICE, ("This node has been banned - releasing all public " - "IPs and setting the generation to INVALID.\n")); - - /* Reset the generation id to 1 to make us ignore any - REQ/REPLY CALL/DMASTER someone sends to us. - We are now banned so we shouldnt service database calls - anymore. - */ - ctdb->vnn_map->generation = INVALID_GENERATION; - for (ctdb_db = ctdb->db_list; ctdb_db != NULL; ctdb_db = ctdb_db->next) { - ctdb_db->generation = INVALID_GENERATION; - } - - /* Recovery daemon will set the recovery mode ACTIVE and freeze - * databases. - */ - - ctdb_release_all_ips(ctdb); -} - int32_t ctdb_control_set_ban_state(struct ctdb_context *ctdb, TDB_DATA indata) { struct ctdb_ban_state *bantime = (struct ctdb_ban_state *)indata.dptr; -- 2.17.1 From a9d0e0b7bae9005d56222e5952f9fec66cb8f491 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 19 Aug 2019 21:48:04 +1000 Subject: [PATCH 098/376] ctdb-daemon: Make node inactive in the NODE_STOP control Currently some of this is supported by a periodic check in the recovery daemon's main_loop(), which notices the flag change, sets recovery mode active and freezes databases. If STOP_NODE returns immediately then the associated recovery can complete and the node can be continued before databases are actually frozen. Instead, immediately do all of the things that make a node inactive. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14087 RN: Stop "ctdb stop" from completing before freezing databases Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs Autobuild-User(master): Amitay Isaacs Autobuild-Date(master): Tue Aug 20 08:32:27 UTC 2019 on sn-devel-184 (cherry picked from commit e9f2e205ee89f4f3d6302cc11b4d0eb2efaf0f53) --- ctdb/server/ctdb_recover.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ctdb/server/ctdb_recover.c b/ctdb/server/ctdb_recover.c index df60a4cb9c0..1654c6d3978 100644 --- a/ctdb/server/ctdb_recover.c +++ b/ctdb/server/ctdb_recover.c @@ -1469,6 +1469,8 @@ int32_t ctdb_control_stop_node(struct ctdb_context *ctdb) DEBUG(DEBUG_ERR, ("Stopping node\n")); ctdb->nodes[ctdb->pnn]->flags |= NODE_FLAGS_STOPPED; + ctdb_node_become_inactive(ctdb); + return 0; } -- 2.17.1 From d61fac0cbe4abe1f90da6aea695690ccdb757765 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sat, 17 Aug 2019 06:59:33 +1200 Subject: [PATCH 099/376] docs: Deprecate "rndc command" for Samba 4.11 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14092 Signed-off-by: Andrew Bartlett Reviewed-by: Andreas Schneider (cherry picked from commit 561e0986ac96c842239b4e8c6509e05c836707b7) --- docs-xml/smbdotconf/domain/rndccommand.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs-xml/smbdotconf/domain/rndccommand.xml b/docs-xml/smbdotconf/domain/rndccommand.xml index d9ac4ea6737..c9a1526c0cd 100644 --- a/docs-xml/smbdotconf/domain/rndccommand.xml +++ b/docs-xml/smbdotconf/domain/rndccommand.xml @@ -1,10 +1,17 @@ + This option is deprecated with Samba 4.11 and will be removed + in future. + This option specifies the path to the name server control utility. + This option is only useful when Samba as an AD DC is + configured with BIND9_FLATFILE for DNS. + The rndc utility should be a part of the bind installation. -- 2.17.1 From aa3ad5c451f38659c1131b20756ad81a903654cb Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Fri, 23 Aug 2019 21:13:22 +1200 Subject: [PATCH 100/376] WHATSNEW: BIND9_FLATFILE / rndc command deprecated Signed-off-by: Andrew Bartlett Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Wed Aug 28 10:48:10 UTC 2019 on sn-devel-184 --- WHATSNEW.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 6a0cc9d72fd..c273117c72f 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -68,6 +68,20 @@ in the following years. If you have a strong requirement for SMB1 (except for supporting old Linux Kernels), please file a bug at https://bugzilla.samba.org and let us know about the details. +BIND9_FLATFILE deprecated +------------------------- + +The BIND9_FLATFILE DNS backend is deprecated in this release and will +be removed in the future. This was only practically useful on a single +domain controller or under expert care and supervision. + +This release therefore deprecates the "rndc command" smb.conf +parameter, which is used to support this configuration. After writing +out a list of DCs permitted to make changes to the DNS Zone "rndc +command" is called with reload to tell the 'named' server if a DC was +added/removed to to the domain. + + NEW FEATURES/CHANGES ==================== @@ -342,6 +356,7 @@ smb.conf changes web port Removed fruit:zero_file_id Changed default False debug encryption New: dump encryption keys False + rndc command Deprecated KNOWN ISSUES -- 2.17.1 From bcfb7749869241a6a85fedca551ae6a4a4dec4fc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 12 Jul 2019 12:10:35 -0700 Subject: [PATCH 101/376] CVE-2019-10197: smbd: separate out impersonation debug info into a new function. Will be called on elsewhere on successful impersonation. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Boehme Reviewed-by: Stefan Metzmacher --- source3/smbd/uid.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index a4bcb747d37..ce8e8d92131 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -279,6 +279,28 @@ static bool check_user_ok(connection_struct *conn, return(True); } +static void print_impersonation_info(connection_struct *conn) +{ + struct smb_filename *cwdfname = NULL; + + if (!CHECK_DEBUGLVL(DBGLVL_INFO)) { + return; + } + + cwdfname = vfs_GetWd(talloc_tos(), conn); + if (cwdfname == NULL) { + return; + } + + DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n", + (int)getuid(), + (int)geteuid(), + (int)getgid(), + (int)getegid(), + cwdfname->base_name); + TALLOC_FREE(cwdfname); +} + /**************************************************************************** Become the user of a connection number without changing the security context stack, but modify the current_user entries. @@ -415,20 +437,7 @@ static bool change_to_user_internal(connection_struct *conn, current_user.done_chdir = true; } - if (CHECK_DEBUGLVL(DBGLVL_INFO)) { - struct smb_filename *cwdfname = vfs_GetWd(talloc_tos(), conn); - if (cwdfname == NULL) { - return false; - } - DBG_INFO("Impersonated user: uid=(%d,%d), gid=(%d,%d), cwd=[%s]\n", - (int)getuid(), - (int)geteuid(), - (int)getgid(), - (int)getegid(), - cwdfname->base_name); - TALLOC_FREE(cwdfname); - } - + print_impersonation_info(conn); return true; } -- 2.17.1 From ae9bdef5c8a2dea2efca6295799a42ba01c3b98d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 11 Jul 2019 17:01:29 +0200 Subject: [PATCH 102/376] CVE-2019-10197: smbd: make sure that change_to_user_internal() always resets current_user.done_chdir We should not leave current_user.done_chdir as true if we didn't call chdir_current_service() with success. This caused problems in when calling vfs_ChDir() in pop_conn_ctx() when chdir_current_service() worked once on one share but later failed on another share. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme --- source3/smbd/uid.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index ce8e8d92131..77a81f60298 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -427,6 +427,7 @@ static bool change_to_user_internal(connection_struct *conn, current_user.conn = conn; current_user.vuid = vuid; current_user.need_chdir = conn->tcon_done; + current_user.done_chdir = false; if (current_user.need_chdir) { ok = chdir_current_service(conn); -- 2.17.1 From d690f6f3c4d82a5ff887df40e2a60a1828eb87eb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 18 Jun 2019 14:04:08 +0200 Subject: [PATCH 103/376] CVE-2019-10197: smbd: make sure we reset current_user.{need,done}_chdir in become_root() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 Signed-off-by: Stefan Metzmacher --- source3/smbd/uid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 77a81f60298..50868ba8572 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -624,6 +624,9 @@ void smbd_become_root(void) } push_conn_ctx(); set_root_sec_ctx(); + + current_user.need_chdir = false; + current_user.done_chdir = false; } /* Unbecome the root user */ -- 2.17.1 From 7b39df0f1449024c8b9f2954a63f0b265c4269e8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 30 Jul 2019 17:16:59 +0200 Subject: [PATCH 104/376] CVE-2019-10197: selftest: make fsrvp_share its own independent subdirectory The next patch will otherwise break the fsrvp related tests. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 Signed-off-by: Stefan Metzmacher --- selftest/target/Samba3.pm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 5c327cab543..4cc2938e8fd 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1449,6 +1449,9 @@ sub provision($$$$$$$$$) my $widelinks_linkdir="$shrdir/widelinks_foo"; push(@dirs,$widelinks_linkdir); + my $fsrvp_shrdir="$shrdir/fsrvp"; + push(@dirs,$fsrvp_shrdir); + my $shadow_tstdir="$shrdir/shadow"; push(@dirs,$shadow_tstdir); my $shadow_mntdir="$shadow_tstdir/mount"; @@ -2024,14 +2027,14 @@ sub provision($$$$$$$$$) guest ok = yes [fsrvp_share] - path = $shrdir + path = $fsrvp_shrdir comment = fake shapshots using rsync vfs objects = shell_snap shadow_copy2 shell_snap:check path command = $fake_snap_pl --check shell_snap:create command = $fake_snap_pl --create shell_snap:delete command = $fake_snap_pl --delete # a relative path here fails, the snapshot dir is no longer found - shadow:snapdir = $shrdir/.snapshots + shadow:snapdir = $fsrvp_shrdir/.snapshots [shadow1] path = $shadow_shrdir -- 2.17.1 From a6ff560aa134fb4fa5ceaba83d29aae0bc398f4d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 16 Jul 2019 15:40:38 +0200 Subject: [PATCH 105/376] CVE-2019-10197: test_smbclient_s3.sh: add regression test for the no permission on share root problem BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 Signed-off-by: Stefan Metzmacher --- selftest/knownfail.d/CVE-2019-10197 | 1 + selftest/target/Samba3.pm | 12 +++++++++ source3/script/tests/test_smbclient_s3.sh | 30 +++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 selftest/knownfail.d/CVE-2019-10197 diff --git a/selftest/knownfail.d/CVE-2019-10197 b/selftest/knownfail.d/CVE-2019-10197 new file mode 100644 index 00000000000..f7056bbf3ad --- /dev/null +++ b/selftest/knownfail.d/CVE-2019-10197 @@ -0,0 +1 @@ +^samba3.blackbox.smbclient_s3.*.noperm.share.regression diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 4cc2938e8fd..9638bb44f08 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1425,6 +1425,9 @@ sub provision($$$$$$$$$) my $ro_shrdir="$shrdir/root-tmp"; push(@dirs,$ro_shrdir); + my $noperm_shrdir="$shrdir/noperm-tmp"; + push(@dirs,$noperm_shrdir); + my $msdfs_shrdir="$shrdir/msdfsshare"; push(@dirs,$msdfs_shrdir); @@ -1495,6 +1498,11 @@ sub provision($$$$$$$$$) chmod 0755, $piddir; + ## + ## Create a directory without permissions to enter + ## + chmod 0000, $noperm_shrdir; + ## ## create ro and msdfs share layout ## @@ -1818,6 +1826,10 @@ sub provision($$$$$$$$$) [ro-tmp] path = $ro_shrdir guest ok = yes +[noperm] + path = $noperm_shrdir + wide links = yes + guest ok = yes [write-list-tmp] path = $shrdir read only = yes diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh index bf033ccd2fb..0bae1d78fac 100755 --- a/source3/script/tests/test_smbclient_s3.sh +++ b/source3/script/tests/test_smbclient_s3.sh @@ -1329,6 +1329,32 @@ EOF fi } +# +# Regression test for CVE-2019-10197 +# we should always get ACCESS_DENIED +# +test_noperm_share_regression() +{ + cmd='$SMBCLIENT -U$USERNAME%$PASSWORD //$SERVER/noperm -I $SERVER_IP $LOCAL_ADDARGS -c "ls;ls" 2>&1' + eval echo "$cmd" + out=`eval $cmd` + ret=$? + if [ $ret -eq 0 ] ; then + echo "$out" + echo "failed accessing no perm share should not work" + return 1 + fi + + num=`echo "$out" | grep 'NT_STATUS_ACCESS_DENIED' | wc -l` + if [ "$num" -ne "2" ] ; then + echo "$out" + echo "failed num[$num] - two NT_STATUS_ACCESS_DENIED lines expected" + return 1 + fi + + return 0 +} + # Test smbclient deltree command test_deltree() { @@ -1857,6 +1883,10 @@ testit "follow local symlinks" \ test_local_symlinks || \ failed=`expr $failed + 1` +testit "noperm share regression" \ + test_noperm_share_regression || \ + failed=`expr $failed + 1` + testit "smbclient deltree command" \ test_deltree || \ failed=`expr $failed + 1` -- 2.17.1 From efd6d670997eff81c94b1ece3814b1da2c3705cb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 11 Jul 2019 17:02:15 +0200 Subject: [PATCH 106/376] CVE-2019-10197: smbd: split change_to_user_impersonate() out of change_to_user_internal() This makes sure we always call chdir_current_service() even when we still impersonated the user. Which is important in order to run the SMB* request within the correct working directory and only if the user has permissions to enter that directory. It makes sure we always update conn->lastused_count in chdir_current_service() for each request. Note that vfs_ChDir() (called from chdir_current_service()) maintains its own cache and avoids calling SMB_VFS_CHDIR() if possible. It means we still avoid syscalls if we get a multiple requests for the same session/tcon tuple. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14035 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme --- selftest/knownfail.d/CVE-2019-10197 | 1 - source3/smbd/uid.c | 21 +++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) delete mode 100644 selftest/knownfail.d/CVE-2019-10197 diff --git a/selftest/knownfail.d/CVE-2019-10197 b/selftest/knownfail.d/CVE-2019-10197 deleted file mode 100644 index f7056bbf3ad..00000000000 --- a/selftest/knownfail.d/CVE-2019-10197 +++ /dev/null @@ -1 +0,0 @@ -^samba3.blackbox.smbclient_s3.*.noperm.share.regression diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c index 50868ba8572..5c39baade5c 100644 --- a/source3/smbd/uid.c +++ b/source3/smbd/uid.c @@ -306,9 +306,9 @@ static void print_impersonation_info(connection_struct *conn) stack, but modify the current_user entries. ****************************************************************************/ -static bool change_to_user_internal(connection_struct *conn, - const struct auth_session_info *session_info, - uint64_t vuid) +static bool change_to_user_impersonate(connection_struct *conn, + const struct auth_session_info *session_info, + uint64_t vuid) { int snum; gid_t gid; @@ -321,7 +321,6 @@ static bool change_to_user_internal(connection_struct *conn, if ((current_user.conn == conn) && (current_user.vuid == vuid) && - (current_user.need_chdir == conn->tcon_done) && (current_user.ut.uid == session_info->unix_token->uid)) { DBG_INFO("Skipping user change - already user\n"); @@ -426,6 +425,20 @@ static bool change_to_user_internal(connection_struct *conn, current_user.conn = conn; current_user.vuid = vuid; + return true; +} + +static bool change_to_user_internal(connection_struct *conn, + const struct auth_session_info *session_info, + uint64_t vuid) +{ + bool ok; + + ok = change_to_user_impersonate(conn, session_info, vuid); + if (!ok) { + return false; + } + current_user.need_chdir = conn->tcon_done; current_user.done_chdir = false; -- 2.17.1 From f04985fe9b54824fb61683c67065da2fdb8f2e1a Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 3 Sep 2019 13:12:16 +0200 Subject: [PATCH 107/376] WHATSNEW: Add release notes for Samba 4.11.0rc3. Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index c273117c72f..eece43fcd9e 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,7 +1,7 @@ Release Announcements ===================== -This is the second release candidate of Samba 4.11. This is *not* +This is the third release candidate of Samba 4.11. This is *not* intended for production environments and is designed for testing purposes only. Please report any defects via the Samba bug reporting system at https://bugzilla.samba.org/. @@ -359,6 +359,51 @@ smb.conf changes rndc command Deprecated +CHANGES SINCE 4.11.0rc2 +======================= + +o Michael Adam + * BUG 13972: Different Device Id for GlusterFS FUSE mount is causing data + loss in CTDB cluster. + +o Jeremy Allison + * BUG 14035: CVE-2019-10197: Permissions check deny can allow user to escape + from the share. + +o Andrew Bartlett + * BUG 14059: ldb: Release ldb 2.0.6 (log database repack so users know what + is happening). + * BUG 14092: docs: Deprecate "rndc command" for Samba 4.11. + +o Tim Beale + * BUG 14059: ldb: Free memory when repacking database. + +o Ralph Boehme + * BUG 14089: vfs_default: Use correct flag in vfswrap_fs_file_id. + * BUG 14090: vfs_glusterfs: Initialize st_ex_file_id, st_ex_itime and + st_ex_iflags. + +o Anoop C S + * BUG 14093: vfs_glusterfs: Enable profiling for file system operations. + +o Aaron Haslett + * BUG 14059: Backport sambadowngradedatabase for v4.11. + +o Stefan Metzmacher + * BUG 14035: CVE-2019-10197: Permissions check deny can allow user to escape + from the share. + +o Christof Schmitt + * BUG 14032: vfs_gpfs: Implement special case for denying owner access to + ACL. + +o Martin Schwenke + * BUG 14084: Avoid marking a node as connected before it can receive packets. + * BUG 14086: Fix onnode test failure with ShellCheck >= 0.4.7. + * BUG 14087: ctdb-daemon: Stop "ctdb stop" from completing before freezing + databases. + + KNOWN ISSUES ============ -- 2.17.1 From c1d9e02d06a158f637475ffeca7a6c3f2fb1d773 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 3 Sep 2019 13:12:53 +0200 Subject: [PATCH 108/376] VERSION: Disable GIT_SNAPSHOT for the 4.11.0rc3 release. Signed-off-by: Karolin Seeger --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 67ae2000ebf..a8742ca9e50 100644 --- a/VERSION +++ b/VERSION @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE=3 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=yes +SAMBA_VERSION_IS_GIT_SNAPSHOT=no ######################################################## # This is for specifying a release nickname # -- 2.17.1 From 96961348432cd1171b99ea2d8e64d4bc9d897f72 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 3 Sep 2019 13:13:47 +0200 Subject: [PATCH 109/376] VERSION: Bump verison up to 4.11.0rc4... and re-enable GIT_SNAPSHOT. Signed-off-by: Karolin Seeger --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index a8742ca9e50..ae98c26560f 100644 --- a/VERSION +++ b/VERSION @@ -87,7 +87,7 @@ SAMBA_VERSION_PRE_RELEASE= # e.g. SAMBA_VERSION_RC_RELEASE=1 # # -> "3.0.0rc1" # ######################################################## -SAMBA_VERSION_RC_RELEASE=3 +SAMBA_VERSION_RC_RELEASE=4 ######################################################## # To mark SVN snapshots this should be set to 'yes' # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE=3 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname # -- 2.17.1 From a279b8883469b524b18e61c30621fe0dd999e054 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 29 Jul 2019 15:31:55 +1000 Subject: [PATCH 110/376] ctdb-tests: Reformat node_has_status() Re-indent and drop non-POSIX left-parenthesis from case labels. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 52227d19735a3305ad633672c70385f443f222f0) --- ctdb/tests/scripts/integration.bash | 94 +++++++++++++++-------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/ctdb/tests/scripts/integration.bash b/ctdb/tests/scripts/integration.bash index 30725c48e53..e2f238d93d4 100644 --- a/ctdb/tests/scripts/integration.bash +++ b/ctdb/tests/scripts/integration.bash @@ -311,53 +311,55 @@ wait_until_ready () # This function is becoming nicely overloaded. Soon it will collapse! :-) node_has_status () { - local pnn="$1" - local status="$2" - - local bits fpat mpat rpat - case "$status" in - (unhealthy) bits="?|?|?|1|*" ;; - (healthy) bits="?|?|?|0|*" ;; - (disconnected) bits="1|*" ;; - (connected) bits="0|*" ;; - (banned) bits="?|1|*" ;; - (unbanned) bits="?|0|*" ;; - (disabled) bits="?|?|1|*" ;; - (enabled) bits="?|?|0|*" ;; - (stopped) bits="?|?|?|?|1|*" ;; - (notstopped) bits="?|?|?|?|0|*" ;; - (frozen) fpat='^[[:space:]]+frozen[[:space:]]+1$' ;; - (unfrozen) fpat='^[[:space:]]+frozen[[:space:]]+0$' ;; - (recovered) rpat='^Recovery mode:RECOVERY \(1\)$' ;; - (notlmaster) rpat="^hash:.* lmaster:${pnn}\$" ;; + local pnn="$1" + local status="$2" + + local bits fpat mpat rpat + case "$status" in + unhealthy) bits="?|?|?|1|*" ;; + healthy) bits="?|?|?|0|*" ;; + disconnected) bits="1|*" ;; + connected) bits="0|*" ;; + banned) bits="?|1|*" ;; + unbanned) bits="?|0|*" ;; + disabled) bits="?|?|1|*" ;; + enabled) bits="?|?|0|*" ;; + stopped) bits="?|?|?|?|1|*" ;; + notstopped) bits="?|?|?|?|0|*" ;; + frozen) fpat='^[[:space:]]+frozen[[:space:]]+1$' ;; + unfrozen) fpat='^[[:space:]]+frozen[[:space:]]+0$' ;; + recovered) rpat='^Recovery mode:RECOVERY \(1\)$' ;; + notlmaster) rpat="^hash:.* lmaster:${pnn}\$" ;; *) - echo "node_has_status: unknown status \"$status\"" - return 1 - esac - - if [ -n "$bits" ] ; then - local out x line - - out=$($CTDB -X status 2>&1) || return 1 - - { - read x - while read line ; do - # This needs to be done in 2 steps to avoid false matches. - local line_bits="${line#|${pnn}|*|}" - [ "$line_bits" = "$line" ] && continue - [ "${line_bits#${bits}}" != "$line_bits" ] && return 0 - done - return 1 - } <<<"$out" # Yay bash! - elif [ -n "$fpat" ] ; then - $CTDB statistics -n "$pnn" | egrep -q "$fpat" - elif [ -n "$rpat" ] ; then - ! $CTDB status -n "$pnn" | egrep -q "$rpat" - else - echo 'node_has_status: unknown mode, neither $bits nor $fpat is set' - return 1 - fi + echo "node_has_status: unknown status \"$status\"" + return 1 + esac + + if [ -n "$bits" ] ; then + local out x line + + out=$($CTDB -X status 2>&1) || return 1 + + { + read x + while read line ; do + # This needs to be done in 2 steps to + # avoid false matches. + local line_bits="${line#|${pnn}|*|}" + [ "$line_bits" = "$line" ] && continue + [ "${line_bits#${bits}}" != "$line_bits" ] && \ + return 0 + done + return 1 + } <<<"$out" # Yay bash! + elif [ -n "$fpat" ] ; then + $CTDB statistics -n "$pnn" | egrep -q "$fpat" + elif [ -n "$rpat" ] ; then + ! $CTDB status -n "$pnn" | egrep -q "$rpat" + else + echo 'node_has_status: unknown mode, neither $bits nor $fpat is set' + return 1 + fi } wait_until_node_has_status () -- 2.17.1 From 6efb59affb25594828e4cc68a30ea41e71f0b124 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 29 Jul 2019 15:40:16 +1000 Subject: [PATCH 111/376] ctdb-tests: Drop unused node statuses frozen/unfrozen Silently drop unused local variable mpat. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 9b09a87326af28877301ad27bcec5bb13744e2b6) --- ctdb/tests/scripts/integration.bash | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ctdb/tests/scripts/integration.bash b/ctdb/tests/scripts/integration.bash index e2f238d93d4..60323e33a97 100644 --- a/ctdb/tests/scripts/integration.bash +++ b/ctdb/tests/scripts/integration.bash @@ -314,7 +314,7 @@ node_has_status () local pnn="$1" local status="$2" - local bits fpat mpat rpat + local bits rpat case "$status" in unhealthy) bits="?|?|?|1|*" ;; healthy) bits="?|?|?|0|*" ;; @@ -326,8 +326,6 @@ node_has_status () enabled) bits="?|?|0|*" ;; stopped) bits="?|?|?|?|1|*" ;; notstopped) bits="?|?|?|?|0|*" ;; - frozen) fpat='^[[:space:]]+frozen[[:space:]]+1$' ;; - unfrozen) fpat='^[[:space:]]+frozen[[:space:]]+0$' ;; recovered) rpat='^Recovery mode:RECOVERY \(1\)$' ;; notlmaster) rpat="^hash:.* lmaster:${pnn}\$" ;; *) @@ -352,12 +350,10 @@ node_has_status () done return 1 } <<<"$out" # Yay bash! - elif [ -n "$fpat" ] ; then - $CTDB statistics -n "$pnn" | egrep -q "$fpat" elif [ -n "$rpat" ] ; then ! $CTDB status -n "$pnn" | egrep -q "$rpat" else - echo 'node_has_status: unknown mode, neither $bits nor $fpat is set' + echo 'node_has_status: unknown mode, neither $bits nor $rpat is set' return 1 fi } -- 2.17.1 From e876b1e85627db8be59bcbcede7154a55f640b00 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 29 Jul 2019 15:45:41 +1000 Subject: [PATCH 112/376] ctdb-tests: Inline handling of recovered and notlmaster statuses BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit bb59073515ee5f7886b5d9a20d7b2805857c2708) --- ctdb/tests/scripts/integration.bash | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ctdb/tests/scripts/integration.bash b/ctdb/tests/scripts/integration.bash index 60323e33a97..d8411edc588 100644 --- a/ctdb/tests/scripts/integration.bash +++ b/ctdb/tests/scripts/integration.bash @@ -314,7 +314,7 @@ node_has_status () local pnn="$1" local status="$2" - local bits rpat + local bits case "$status" in unhealthy) bits="?|?|?|1|*" ;; healthy) bits="?|?|?|0|*" ;; @@ -326,8 +326,16 @@ node_has_status () enabled) bits="?|?|0|*" ;; stopped) bits="?|?|?|?|1|*" ;; notstopped) bits="?|?|?|?|0|*" ;; - recovered) rpat='^Recovery mode:RECOVERY \(1\)$' ;; - notlmaster) rpat="^hash:.* lmaster:${pnn}\$" ;; + recovered) + ! $CTDB status -n "$pnn" | \ + grep -Eq '^Recovery mode:RECOVERY \(1\)$' + return + ;; + notlmaster) + ! $CTDB status -n "$pnn" | \ + grep -Eq "^hash:.* lmaster:${pnn}\$" + return + ;; *) echo "node_has_status: unknown status \"$status\"" return 1 @@ -350,10 +358,8 @@ node_has_status () done return 1 } <<<"$out" # Yay bash! - elif [ -n "$rpat" ] ; then - ! $CTDB status -n "$pnn" | egrep -q "$rpat" else - echo 'node_has_status: unknown mode, neither $bits nor $rpat is set' + echo 'node_has_status: unknown mode, $bits not set' return 1 fi } -- 2.17.1 From 7e004230708001878e6b278aab32b6854289dc6a Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 29 Jul 2019 16:43:09 +1000 Subject: [PATCH 113/376] ctdb-tests: Handle special cases first and return All the other cases involve matching bits. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit bff1a3a548a2cace997b767d78bb824438664cb7) --- ctdb/tests/scripts/integration.bash | 59 ++++++++++++++--------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/ctdb/tests/scripts/integration.bash b/ctdb/tests/scripts/integration.bash index d8411edc588..3fb6f9ade5e 100644 --- a/ctdb/tests/scripts/integration.bash +++ b/ctdb/tests/scripts/integration.bash @@ -314,6 +314,19 @@ node_has_status () local pnn="$1" local status="$2" + case "$status" in + recovered) + ! $CTDB status -n "$pnn" | \ + grep -Eq '^Recovery mode:RECOVERY \(1\)$' + return + ;; + notlmaster) + ! $CTDB status -n "$pnn" | \ + grep -Eq "^hash:.* lmaster:${pnn}\$" + return + ;; + esac + local bits case "$status" in unhealthy) bits="?|?|?|1|*" ;; @@ -326,42 +339,26 @@ node_has_status () enabled) bits="?|?|0|*" ;; stopped) bits="?|?|?|?|1|*" ;; notstopped) bits="?|?|?|?|0|*" ;; - recovered) - ! $CTDB status -n "$pnn" | \ - grep -Eq '^Recovery mode:RECOVERY \(1\)$' - return - ;; - notlmaster) - ! $CTDB status -n "$pnn" | \ - grep -Eq "^hash:.* lmaster:${pnn}\$" - return - ;; *) echo "node_has_status: unknown status \"$status\"" return 1 esac - - if [ -n "$bits" ] ; then - local out x line - - out=$($CTDB -X status 2>&1) || return 1 - - { - read x - while read line ; do - # This needs to be done in 2 steps to - # avoid false matches. - local line_bits="${line#|${pnn}|*|}" - [ "$line_bits" = "$line" ] && continue - [ "${line_bits#${bits}}" != "$line_bits" ] && \ - return 0 - done - return 1 - } <<<"$out" # Yay bash! - else - echo 'node_has_status: unknown mode, $bits not set' + local out x line + + out=$($CTDB -X status 2>&1) || return 1 + + { + read x + while read line ; do + # This needs to be done in 2 steps to + # avoid false matches. + local line_bits="${line#|${pnn}|*|}" + [ "$line_bits" = "$line" ] && continue + [ "${line_bits#${bits}}" != "$line_bits" ] && \ + return 0 + done return 1 - fi + } <<<"$out" # Yay bash! } wait_until_node_has_status () -- 2.17.1 From 4a5c554508b14be280bddb7c16688868c980abf0 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 29 Jul 2019 16:45:07 +1000 Subject: [PATCH 114/376] ctdb-tests: Don't retrieve the VNN map from target node for notlmaster Use the VNN map from the node running node_has_status(). This means that wait_until_node_has_status 1 notlmaster 10 0 will run "ctdb status" on node 0 and check (for up to 10 seconds) if node 1 is in the VNN map. If the LMASTER capability has been dropped on node 1 then the above will wait for the VNN map to be updated on node 0. This will happen as part of the recovery that is triggered by the change of LMASTER capability. The next command will then only be able to attach to $TESTDB after the recovery is complete thus guaranteeing a sane state for the test to continue. This stops simple/79_volatile_db_traverse.sh from going into recovery during the traverse or at some other inconvenient time. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 53daeb2f878af1634a26e05cb86d87e2faf20173) --- ctdb/tests/scripts/integration.bash | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ctdb/tests/scripts/integration.bash b/ctdb/tests/scripts/integration.bash index 3fb6f9ade5e..a4d45fb9ac2 100644 --- a/ctdb/tests/scripts/integration.bash +++ b/ctdb/tests/scripts/integration.bash @@ -321,8 +321,7 @@ node_has_status () return ;; notlmaster) - ! $CTDB status -n "$pnn" | \ - grep -Eq "^hash:.* lmaster:${pnn}\$" + ! $CTDB status | grep -Eq "^hash:.* lmaster:${pnn}\$" return ;; esac -- 2.17.1 From a03443efef6488a5b2dc74962f77070c0c8ecb06 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Wed, 21 Aug 2019 14:35:09 +1000 Subject: [PATCH 115/376] ctdb-recoverd: Only check for LMASTER nodes in the VNN map BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 5d655ac6f2ff82f8f1c89b06870d600a1a3c7a8a) --- ctdb/server/ctdb_recoverd.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index 652bf9ce4ea..a190d0c9985 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -2989,13 +2989,19 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, return; } - /* verify that all active nodes in the nodemap also exist in - the vnnmap. + /* + * Verify that all active lmaster nodes in the nodemap also + * exist in the vnnmap */ for (j=0; jnum; j++) { if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) { continue; } + if (! ctdb_node_has_capabilities(rec->caps, + ctdb->nodes[j]->pnn, + CTDB_CAP_LMASTER)) { + continue; + } if (nodemap->nodes[j].pnn == pnn) { continue; } @@ -3006,8 +3012,8 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, } } if (i == vnnmap->size) { - DEBUG(DEBUG_ERR, (__location__ " Node %u is active in the nodemap but did not exist in the vnnmap\n", - nodemap->nodes[j].pnn)); + D_ERR("Active LMASTER node %u is not in the vnnmap\n", + nodemap->nodes[j].pnn); ctdb_set_culprit(rec, nodemap->nodes[j].pnn); do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap); return; -- 2.17.1 From 9063f5dde3f9fc43037539e4424944400c00ddb5 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 29 Jul 2019 17:22:50 +1000 Subject: [PATCH 116/376] ctdb-tests: Strengthen volatile DB traverse test Check the record count more often, from multiple nodes. Add a case with multiple records. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit ca4df06080709adf0cbebc95b0a70b4090dad5ba) --- ctdb/tests/simple/79_volatile_db_traverse.sh | 67 +++++++++++++++----- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/ctdb/tests/simple/79_volatile_db_traverse.sh b/ctdb/tests/simple/79_volatile_db_traverse.sh index af7e962f579..7f3007d5105 100755 --- a/ctdb/tests/simple/79_volatile_db_traverse.sh +++ b/ctdb/tests/simple/79_volatile_db_traverse.sh @@ -42,11 +42,56 @@ try_command_on_node 0 $CTDB writekey "$TESTDB" "foo" "bar0" echo "write foo=bar1 on node 1" try_command_on_node 1 $CTDB writekey "$TESTDB" "foo" "bar1" -echo "do traverse on node 0" -try_command_on_node -v 0 $CTDB catdb "$TESTDB" +echo -echo "do traverse on node 1" -try_command_on_node -v 1 $CTDB catdb "$TESTDB" +check_db_num_records () +{ + local node="$1" + local db="$2" + local n="$3" + + echo "Checking on node ${node} to ensure ${db} has ${n} records..." + try_command_on_node "$node" "${CTDB} catdb ${db}" + + num=$(sed -n -e 's|^Dumped \(.*\) records$|\1|p' "$outfile") + if [ "$num" = "$n" ] ; then + echo "OK: Number of records=${num}" + echo + else + echo "BAD: There were ${num} (!= ${n}) records" + cat "$outfile" + exit 1 + fi +} + +check_db_num_records 0 "$TESTDB" 1 +check_db_num_records 1 "$TESTDB" 1 + +cat < Date: Tue, 13 Aug 2019 14:45:33 +1000 Subject: [PATCH 117/376] ctdb-tests: Clear deleted record via recovery instead of vacuuming This test has been flapping because sometimes the record is not vacuumed within the expected time period, perhaps even because the check for the record can interfere with vacuuming. However, instead of waiting for vacuuming the record can be cleared by doing a recovery. This should be much more reliable. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 RN: Fix flapping CTDB tests Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs Autobuild-User(master): Martin Schwenke Autobuild-Date(master): Wed Aug 21 13:06:57 UTC 2019 on sn-devel-184 (cherry picked from commit 71ad473ba805abe23bbe6c1a1290612e448e73f3) --- .../simple/69_recovery_resurrect_deleted.sh | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/ctdb/tests/simple/69_recovery_resurrect_deleted.sh b/ctdb/tests/simple/69_recovery_resurrect_deleted.sh index 8126c49b83c..f6c72c59f2a 100755 --- a/ctdb/tests/simple/69_recovery_resurrect_deleted.sh +++ b/ctdb/tests/simple/69_recovery_resurrect_deleted.sh @@ -54,18 +54,11 @@ database_has_zero_records () return 0 } -echo "Get vacuum interval" -try_command_on_node -v $second $CTDB getvar VacuumInterval -vacuum_interval="${out#* = }" - -echo "Wait until vacuuming deletes the record on active nodes" -# Why 4? Steps are: -# 1. Original node processes delete queue, asks lmaster to fetch -# 2. lmaster recoverd fetches -# 3. lmaster processes delete queue -# If vacuuming is just missed then need an extra interval -t=$((vacuum_interval * 4)) -wait_until "${t}/10" database_has_zero_records +echo "Trigger a recovery" +try_command_on_node "$second" $CTDB recover + +echo "Checking that database has 0 records" +database_has_zero_records echo "Continue node ${first}" try_command_on_node $first $CTDB continue -- 2.17.1 From 8b680d309798d91e4658a358831e957aaffa480b Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Tue, 27 Aug 2019 12:13:51 +1000 Subject: [PATCH 118/376] ctdb-recoverd: Fix typo in previous fix BUG: https://bugzilla.samba.org/show_bug.cgi?id=14085 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs Autobuild-User(master): Amitay Isaacs Autobuild-Date(master): Tue Aug 27 15:29:11 UTC 2019 on sn-devel-184 (cherry picked from commit 8190993d99284162bd8699780248bb2edfec2673) --- ctdb/server/ctdb_recoverd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_recoverd.c b/ctdb/server/ctdb_recoverd.c index a190d0c9985..3d5b727715a 100644 --- a/ctdb/server/ctdb_recoverd.c +++ b/ctdb/server/ctdb_recoverd.c @@ -2998,7 +2998,7 @@ static void main_loop(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, continue; } if (! ctdb_node_has_capabilities(rec->caps, - ctdb->nodes[j]->pnn, + nodemap->nodes[j].pnn, CTDB_CAP_LMASTER)) { continue; } -- 2.17.1 From 0e96b2cb506f278562fe21b0b8d47da276b939c6 Mon Sep 17 00:00:00 2001 From: Poornima G Date: Wed, 24 Jul 2019 15:15:33 +0530 Subject: [PATCH 119/376] vfs_glusterfs: Use pthreadpool for scheduling aio operations BUG: https://bugzilla.samba.org/show_bug.cgi?id=14098 Signed-off-by: Poornima G Reviewed-by: Guenther Deschner Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Fri Aug 23 18:40:08 UTC 2019 on sn-devel-184 (cherry picked from commit d8863dd8cb74bb0534457ca930a71e77c367d994) --- source3/modules/vfs_glusterfs.c | 562 +++++++++++++++++--------------- 1 file changed, 294 insertions(+), 268 deletions(-) diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index 483d28397f8..afb34b4b47c 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -45,14 +45,11 @@ #include "lib/util/sys_rw.h" #include "smbprofile.h" #include "modules/posixacl_xattr.h" +#include "lib/pthreadpool/pthreadpool_tevent.h" #define DEFAULT_VOLFILE_SERVER "localhost" #define GLUSTER_NAME_MAX 255 -static int read_fd = -1; -static int write_fd = -1; -static struct tevent_fd *aio_read_event = NULL; - /** * Helper to convert struct stat to struct stat_ex. */ @@ -713,326 +710,283 @@ static ssize_t vfs_gluster_pread(struct vfs_handle_struct *handle, return ret; } -struct glusterfs_aio_state; - -struct glusterfs_aio_wrapper { - struct glusterfs_aio_state *state; -}; - -struct glusterfs_aio_state { +struct vfs_gluster_pread_state { ssize_t ret; - struct tevent_req *req; - bool cancelled; + glfs_fd_t *fd; + void *buf; + size_t count; + off_t offset; + struct vfs_aio_state vfs_aio_state; - struct timespec start; SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes); }; -static int aio_wrapper_destructor(struct glusterfs_aio_wrapper *wrap) -{ - if (wrap->state != NULL) { - wrap->state->cancelled = true; - } - - return 0; -} +static void vfs_gluster_pread_do(void *private_data); +static void vfs_gluster_pread_done(struct tevent_req *subreq); +static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state); -/* - * This function is the callback that will be called on glusterfs - * threads once the async IO submitted is complete. To notify - * Samba of the completion we use a pipe based queue. - */ -#ifdef HAVE_GFAPI_VER_7_6 -static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, - struct glfs_stat *prestat, - struct glfs_stat *poststat, - void *data) -#else -static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data) -#endif +static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct + *handle, TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + files_struct *fsp, + void *data, size_t n, + off_t offset) { - struct glusterfs_aio_state *state = NULL; - int sts = 0; - struct timespec end; - - state = (struct glusterfs_aio_state *)data; + struct vfs_gluster_pread_state *state; + struct tevent_req *req, *subreq; - PROFILE_TIMESTAMP(&end); + glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + if (glfd == NULL) { + DBG_ERR("Failed to fetch gluster fd\n"); + return NULL; + } - if (ret < 0) { - state->ret = -1; - state->vfs_aio_state.error = errno; - } else { - state->ret = ret; + req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pread_state); + if (req == NULL) { + return NULL; } - state->vfs_aio_state.duration = nsec_time_diff(&end, &state->start); - SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes); + state->ret = -1; + state->fd = glfd; + state->buf = data; + state->count = n; + state->offset = offset; - /* - * Write the state pointer to glusterfs_aio_state to the - * pipe, so we can call tevent_req_done() from the main thread, - * because tevent_req_done() is not designed to be executed in - * the multithread environment, so tevent_req_done() must be - * executed from the smbd main thread. - * - * write(2) on pipes with sizes under _POSIX_PIPE_BUF - * in size is atomic, without this, the use op pipes in this - * code would not work. - * - * sys_write is a thin enough wrapper around write(2) - * that we can trust it here. - */ + SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p, + state->profile_bytes, n); + SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes); - sts = sys_write(write_fd, &state, sizeof(struct glusterfs_aio_state *)); - if (sts < 0) { - DEBUG(0,("\nWrite to pipe failed (%s)", strerror(errno))); + subreq = pthreadpool_tevent_job_send( + state, ev, handle->conn->sconn->pool, + vfs_gluster_pread_do, state); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, vfs_gluster_pread_done, req); + + talloc_set_destructor(state, vfs_gluster_pread_state_destructor); - return; + return req; } -/* - * Read each req off the pipe and process it. - */ -static void aio_tevent_fd_done(struct tevent_context *event_ctx, - struct tevent_fd *fde, - uint16_t flags, void *data) +static void vfs_gluster_pread_do(void *private_data) { - struct tevent_req *req = NULL; - struct glusterfs_aio_state *state = NULL; - int sts = 0; + struct vfs_gluster_pread_state *state = talloc_get_type_abort( + private_data, struct vfs_gluster_pread_state); + struct timespec start_time; + struct timespec end_time; - /* - * read(2) on pipes is atomic if the needed data is available - * in the pipe, per SUS and POSIX. Because we always write - * to the pipe in sizeof(struct tevent_req *) chunks, we can - * always read in those chunks, atomically. - * - * sys_read is a thin enough wrapper around read(2) that we - * can trust it here. - */ + SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes); - sts = sys_read(read_fd, &state, sizeof(struct glusterfs_aio_state *)); + PROFILE_TIMESTAMP(&start_time); - if (sts < 0) { - DEBUG(0,("\nRead from pipe failed (%s)", strerror(errno))); - } + do { +#ifdef HAVE_GFAPI_VER_7_6 + state->ret = glfs_pread(state->fd, state->buf, state->count, + state->offset, 0, NULL); +#else + state->ret = glfs_pread(state->fd, state->buf, state->count, + state->offset, 0); +#endif + } while ((state->ret == -1) && (errno == EINTR)); - /* if we've cancelled the op, there is no req, so just clean up. */ - if (state->cancelled == true) { - TALLOC_FREE(state); - return; + if (state->ret == -1) { + state->vfs_aio_state.error = errno; } - req = state->req; + PROFILE_TIMESTAMP(&end_time); - if (req) { - tevent_req_done(req); - } - return; + state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time); + + SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes); } -static bool init_gluster_aio(struct vfs_handle_struct *handle) +static int vfs_gluster_pread_state_destructor(struct vfs_gluster_pread_state *state) { - int fds[2]; - int ret = -1; + return -1; +} - if (read_fd != -1) { +static void vfs_gluster_pread_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct vfs_gluster_pread_state *state = tevent_req_data( + req, struct vfs_gluster_pread_state); + int ret; + + ret = pthreadpool_tevent_job_recv(subreq); + TALLOC_FREE(subreq); + SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes); + talloc_set_destructor(state, NULL); + if (ret != 0) { + if (ret != EAGAIN) { + tevent_req_error(req, ret); + return; + } /* - * Already initialized. + * If we get EAGAIN from pthreadpool_tevent_job_recv() this + * means the lower level pthreadpool failed to create a new + * thread. Fallback to sync processing in that case to allow + * some progress for the client. */ - return true; - } - - ret = pipe(fds); - if (ret == -1) { - goto fail; - } - - read_fd = fds[0]; - write_fd = fds[1]; - - aio_read_event = tevent_add_fd(handle->conn->sconn->ev_ctx, - NULL, - read_fd, - TEVENT_FD_READ, - aio_tevent_fd_done, - NULL); - if (aio_read_event == NULL) { - goto fail; + vfs_gluster_pread_do(state); } - return true; -fail: - TALLOC_FREE(aio_read_event); - if (read_fd != -1) { - close(read_fd); - close(write_fd); - read_fd = -1; - write_fd = -1; - } - return false; + tevent_req_done(req); } -static struct glusterfs_aio_state *aio_state_create(TALLOC_CTX *mem_ctx) +static ssize_t vfs_gluster_pread_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) { - struct tevent_req *req = NULL; - struct glusterfs_aio_state *state = NULL; - struct glusterfs_aio_wrapper *wrapper = NULL; + struct vfs_gluster_pread_state *state = tevent_req_data( + req, struct vfs_gluster_pread_state); - req = tevent_req_create(mem_ctx, &wrapper, struct glusterfs_aio_wrapper); - - if (req == NULL) { - return NULL; + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; } - state = talloc_zero(NULL, struct glusterfs_aio_state); - - if (state == NULL) { - TALLOC_FREE(req); - return NULL; - } + *vfs_aio_state = state->vfs_aio_state; + return state->ret; +} - talloc_set_destructor(wrapper, aio_wrapper_destructor); - state->cancelled = false; - state->req = req; +struct vfs_gluster_pwrite_state { + ssize_t ret; + glfs_fd_t *fd; + const void *buf; + size_t count; + off_t offset; - wrapper->state = state; + struct vfs_aio_state vfs_aio_state; + SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes); +}; - return state; -} +static void vfs_gluster_pwrite_do(void *private_data); +static void vfs_gluster_pwrite_done(struct tevent_req *subreq); +static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state); -static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct +static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct tevent_context *ev, files_struct *fsp, - void *data, size_t n, + const void *data, size_t n, off_t offset) { - struct glusterfs_aio_state *state = NULL; - struct tevent_req *req = NULL; - int ret = 0; - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + struct tevent_req *req, *subreq; + struct vfs_gluster_pwrite_state *state; + glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { DBG_ERR("Failed to fetch gluster fd\n"); return NULL; } - state = aio_state_create(mem_ctx); - - if (state == NULL) { + req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_pwrite_state); + if (req == NULL) { return NULL; } - req = state->req; + state->ret = -1; + state->fd = glfd; + state->buf = data; + state->count = n; + state->offset = offset; - if (!init_gluster_aio(handle)) { - tevent_req_error(req, EIO); - return tevent_req_post(req, ev); - } - - /* - * aio_glusterfs_done and aio_tevent_fd_done() - * use the raw tevent context. We need to use - * tevent_req_defer_callback() in order to - * use the event context we're started with. - */ - tevent_req_defer_callback(req, ev); - - SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p, + SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p, state->profile_bytes, n); - PROFILE_TIMESTAMP(&state->start); - ret = glfs_pread_async(glfd, data, n, offset, 0, aio_glusterfs_done, - state); - if (ret < 0) { - tevent_req_error(req, -ret); + SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes); + + subreq = pthreadpool_tevent_job_send( + state, ev, handle->conn->sconn->pool, + vfs_gluster_pwrite_do, state); + if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, vfs_gluster_pwrite_done, req); + + talloc_set_destructor(state, vfs_gluster_pwrite_state_destructor); return req; } -static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct - *handle, TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - files_struct *fsp, - const void *data, size_t n, - off_t offset) +static void vfs_gluster_pwrite_do(void *private_data) { - struct glusterfs_aio_state *state = NULL; - struct tevent_req *req = NULL; - int ret = 0; - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); - - if (glfd == NULL) { - DBG_ERR("Failed to fetch gluster fd\n"); - return NULL; - } + struct vfs_gluster_pwrite_state *state = talloc_get_type_abort( + private_data, struct vfs_gluster_pwrite_state); + struct timespec start_time; + struct timespec end_time; - state = aio_state_create(mem_ctx); + SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes); - if (state == NULL) { - return NULL; - } + PROFILE_TIMESTAMP(&start_time); - req = state->req; + do { +#ifdef HAVE_GFAPI_VER_7_6 + state->ret = glfs_pwrite(state->fd, state->buf, state->count, + state->offset, 0, NULL, NULL); +#else + state->ret = glfs_pwrite(state->fd, state->buf, state->count, + state->offset, 0); +#endif + } while ((state->ret == -1) && (errno == EINTR)); - if (!init_gluster_aio(handle)) { - tevent_req_error(req, EIO); - return tevent_req_post(req, ev); + if (state->ret == -1) { + state->vfs_aio_state.error = errno; } - /* - * aio_glusterfs_done and aio_tevent_fd_done() - * use the raw tevent context. We need to use - * tevent_req_defer_callback() in order to - * use the event context we're started with. - */ - tevent_req_defer_callback(req, ev); + PROFILE_TIMESTAMP(&end_time); - SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pwrite, profile_p, - state->profile_bytes, n); - PROFILE_TIMESTAMP(&state->start); - ret = glfs_pwrite_async(glfd, data, n, offset, 0, aio_glusterfs_done, - state); - if (ret < 0) { - tevent_req_error(req, -ret); - return tevent_req_post(req, ev); - } + state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time); - return req; + SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes); } -static ssize_t vfs_gluster_recv(struct tevent_req *req, - struct vfs_aio_state *vfs_aio_state) +static int vfs_gluster_pwrite_state_destructor(struct vfs_gluster_pwrite_state *state) { - struct glusterfs_aio_wrapper *wrapper = NULL; - int ret = 0; + return -1; +} - wrapper = tevent_req_data(req, struct glusterfs_aio_wrapper); +static void vfs_gluster_pwrite_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct vfs_gluster_pwrite_state *state = tevent_req_data( + req, struct vfs_gluster_pwrite_state); + int ret; - if (wrapper == NULL) { - return -1; + ret = pthreadpool_tevent_job_recv(subreq); + TALLOC_FREE(subreq); + SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes); + talloc_set_destructor(state, NULL); + if (ret != 0) { + if (ret != EAGAIN) { + tevent_req_error(req, ret); + return; + } + /* + * If we get EAGAIN from pthreadpool_tevent_job_recv() this + * means the lower level pthreadpool failed to create a new + * thread. Fallback to sync processing in that case to allow + * some progress for the client. + */ + vfs_gluster_pwrite_do(state); } - if (wrapper->state == NULL) { - return -1; - } + tevent_req_done(req); +} + +static ssize_t vfs_gluster_pwrite_recv(struct tevent_req *req, + struct vfs_aio_state *vfs_aio_state) +{ + struct vfs_gluster_pwrite_state *state = tevent_req_data( + req, struct vfs_gluster_pwrite_state); if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { return -1; } - *vfs_aio_state = wrapper->state->vfs_aio_state; - ret = wrapper->state->ret; + *vfs_aio_state = state->vfs_aio_state; - /* Clean up the state, it is in a NULL context. */ - - TALLOC_FREE(wrapper->state); - - return ret; + return state->ret; } static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle, @@ -1113,60 +1067,132 @@ static int vfs_gluster_rename(struct vfs_handle_struct *handle, return ret; } +struct vfs_gluster_fsync_state { + ssize_t ret; + glfs_fd_t *fd; + + struct vfs_aio_state vfs_aio_state; + SMBPROFILE_BYTES_ASYNC_STATE(profile_bytes); +}; + +static void vfs_gluster_fsync_do(void *private_data); +static void vfs_gluster_fsync_done(struct tevent_req *subreq); +static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state); + static struct tevent_req *vfs_gluster_fsync_send(struct vfs_handle_struct *handle, TALLOC_CTX *mem_ctx, struct tevent_context *ev, files_struct *fsp) { - struct tevent_req *req = NULL; - struct glusterfs_aio_state *state = NULL; - int ret = 0; - glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); + struct tevent_req *req, *subreq; + struct vfs_gluster_fsync_state *state; + glfs_fd_t *glfd = vfs_gluster_fetch_glfd(handle, fsp); if (glfd == NULL) { DBG_ERR("Failed to fetch gluster fd\n"); return NULL; } - state = aio_state_create(mem_ctx); - - if (state == NULL) { + req = tevent_req_create(mem_ctx, &state, struct vfs_gluster_fsync_state); + if (req == NULL) { return NULL; } - req = state->req; + state->ret = -1; + state->fd = glfd; - if (!init_gluster_aio(handle)) { - tevent_req_error(req, EIO); + SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p, + state->profile_bytes, 0); + SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes); + + subreq = pthreadpool_tevent_job_send( + state, ev, handle->conn->sconn->pool, vfs_gluster_fsync_do, state); + if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } + tevent_req_set_callback(subreq, vfs_gluster_fsync_done, req); - /* - * aio_glusterfs_done and aio_tevent_fd_done() - * use the raw tevent context. We need to use - * tevent_req_defer_callback() in order to - * use the event context we're started with. - */ - tevent_req_defer_callback(req, ev); + talloc_set_destructor(state, vfs_gluster_fsync_state_destructor); - SMBPROFILE_BYTES_ASYNC_START(syscall_asys_fsync, profile_p, - state->profile_bytes, 0); - PROFILE_TIMESTAMP(&state->start); - ret = glfs_fsync_async(glfd, aio_glusterfs_done, state); - if (ret < 0) { - tevent_req_error(req, -ret); - return tevent_req_post(req, ev); - } return req; } +static void vfs_gluster_fsync_do(void *private_data) +{ + struct vfs_gluster_fsync_state *state = talloc_get_type_abort( + private_data, struct vfs_gluster_fsync_state); + struct timespec start_time; + struct timespec end_time; + + SMBPROFILE_BYTES_ASYNC_SET_BUSY(state->profile_bytes); + + PROFILE_TIMESTAMP(&start_time); + + do { +#ifdef HAVE_GFAPI_VER_7_6 + state->ret = glfs_fsync(state->fd, NULL, NULL); +#else + state->ret = glfs_fsync(state->fd); +#endif + } while ((state->ret == -1) && (errno == EINTR)); + + if (state->ret == -1) { + state->vfs_aio_state.error = errno; + } + + PROFILE_TIMESTAMP(&end_time); + + state->vfs_aio_state.duration = nsec_time_diff(&end_time, &start_time); + + SMBPROFILE_BYTES_ASYNC_SET_IDLE(state->profile_bytes); +} + +static int vfs_gluster_fsync_state_destructor(struct vfs_gluster_fsync_state *state) +{ + return -1; +} + +static void vfs_gluster_fsync_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct vfs_gluster_fsync_state *state = tevent_req_data( + req, struct vfs_gluster_fsync_state); + int ret; + + ret = pthreadpool_tevent_job_recv(subreq); + TALLOC_FREE(subreq); + SMBPROFILE_BYTES_ASYNC_END(state->profile_bytes); + talloc_set_destructor(state, NULL); + if (ret != 0) { + if (ret != EAGAIN) { + tevent_req_error(req, ret); + return; + } + /* + * If we get EAGAIN from pthreadpool_tevent_job_recv() this + * means the lower level pthreadpool failed to create a new + * thread. Fallback to sync processing in that case to allow + * some progress for the client. + */ + vfs_gluster_fsync_do(state); + } + + tevent_req_done(req); +} + static int vfs_gluster_fsync_recv(struct tevent_req *req, struct vfs_aio_state *vfs_aio_state) { - /* - * Use implicit conversion ssize_t->int - */ - return vfs_gluster_recv(req, vfs_aio_state); + struct vfs_gluster_fsync_state *state = tevent_req_data( + req, struct vfs_gluster_fsync_state); + + if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) { + return -1; + } + + *vfs_aio_state = state->vfs_aio_state; + return state->ret; } static int vfs_gluster_stat(struct vfs_handle_struct *handle, @@ -1862,10 +1888,10 @@ static struct vfs_fn_pointers glusterfs_fns = { .close_fn = vfs_gluster_close, .pread_fn = vfs_gluster_pread, .pread_send_fn = vfs_gluster_pread_send, - .pread_recv_fn = vfs_gluster_recv, + .pread_recv_fn = vfs_gluster_pread_recv, .pwrite_fn = vfs_gluster_pwrite, .pwrite_send_fn = vfs_gluster_pwrite_send, - .pwrite_recv_fn = vfs_gluster_recv, + .pwrite_recv_fn = vfs_gluster_pwrite_recv, .lseek_fn = vfs_gluster_lseek, .sendfile_fn = vfs_gluster_sendfile, .recvfile_fn = vfs_gluster_recvfile, -- 2.17.1 From 0358b3f9bc1e557a639ec63670d8c29c135e54f5 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Sat, 6 Jul 2019 23:24:43 +1200 Subject: [PATCH 120/376] ldb: do not allow adding a DN as a base to itself If you try to add a dn to itself, it expands as it goes. The resulting loop cannot end well. It looks like this in Python: dn = ldb.Dn(ldb.Ldb(), 'CN=y,DC=x') dn.add_base(dn) Signed-off-by: Douglas Bagnall Reviewed-by: Gary Lockyer (cherry picked from commit 19a13cbe0681b3996c33f7449f69b0fb0dc5d640) --- lib/ldb/common/ldb_dn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c index 2e98f391467..eccb4a0ce4b 100644 --- a/lib/ldb/common/ldb_dn.c +++ b/lib/ldb/common/ldb_dn.c @@ -1357,6 +1357,10 @@ bool ldb_dn_add_base(struct ldb_dn *dn, struct ldb_dn *base) return false; } + if (dn == base) { + return false; /* or we will visit infinity */ + } + if (dn->components) { unsigned int i; -- 2.17.1 From 7cf6afba65641f48a5e2c326464fd97fd9f4173c Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Fri, 8 Mar 2019 12:12:00 +1300 Subject: [PATCH 121/376] ldb_dn: free dn components on explode failure Signed-off-by: Douglas Bagnall Reviewed-by: Noel Power (cherry picked from commit b136f153b83d80a91ec9d5350fdf08412d881964) --- lib/ldb/common/ldb_dn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c index eccb4a0ce4b..23a817edf65 100644 --- a/lib/ldb/common/ldb_dn.c +++ b/lib/ldb/common/ldb_dn.c @@ -340,7 +340,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) /* Components data space is allocated here once */ data = talloc_array(dn->components, char, strlen(parse_dn) + 1); if (!data) { - return false; + goto failed; } p = parse_dn; -- 2.17.1 From 57f00784ffac527a0f9b830339bba24784f2e294 Mon Sep 17 00:00:00 2001 From: Swen Schillig Date: Wed, 31 Jul 2019 10:27:37 +0200 Subject: [PATCH 122/376] ldb: Fix mem-leak if talloc_realloc fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of a failing talloc_realloc(), the only reference to the originally allocated memory is overwritten. Instead use a temp var until success is verified. Signed-off-by: Swen Schillig Reviewed-by: Christof Schmitt Reviewed-by: Matthias Dieter Wallnöfer Reviewed-by: Andrew Bartlett (cherry picked from commit 99b4791cfe423b19f1f21d5f9fb42157336019f1) --- lib/ldb/common/ldb_dn.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c index 23a817edf65..9b2fa966e11 100644 --- a/lib/ldb/common/ldb_dn.c +++ b/lib/ldb/common/ldb_dn.c @@ -376,6 +376,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) } if (in_ex_value && *p == '>') { + struct ldb_dn_ext_component *ext_comp = NULL; const struct ldb_dn_extended_syntax *ext_syntax; struct ldb_val ex_val = { .data = (uint8_t *)ex_value, @@ -388,15 +389,19 @@ static bool ldb_dn_explode(struct ldb_dn *dn) /* Process name and ex_value */ - dn->ext_components = talloc_realloc(dn, - dn->ext_components, - struct ldb_dn_ext_component, - dn->ext_comp_num + 1); - if ( ! dn->ext_components) { + ext_comp = talloc_realloc( + dn, + dn->ext_components, + struct ldb_dn_ext_component, + dn->ext_comp_num + 1); + + if (ext_comp == NULL) { /* ouch ! */ goto failed; } + dn->ext_components = ext_comp; + ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, ex_name); if (!ext_syntax) { /* We don't know about this type of extended DN */ -- 2.17.1 From 9c677a274d49026105c72c5b4767b1d88eff77fa Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 26 Aug 2019 13:04:07 +1200 Subject: [PATCH 123/376] ldb: Correct Pigeonhole principle validation in ldb_filter_attrs() Thankfully this only fails if the DB is corrupt and has a duplicate record. The test was at the wrong end of the loop, and was for the wrong boundary condition. A write after the end of the array would occour before the condition was hit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13695 Signed-off-by: Andrew Bartlett Reviewed-by: Gary Lockyer (cherry picked from commit b1eec5b196e3d5a5716a5c74cf669ceaa5c0301f) --- lib/ldb/common/ldb_pack.c | 31 +- lib/ldb/tests/ldb_filter_attrs_test.c | 986 ++++++++++++++++++++++++++ lib/ldb/wscript | 5 + 3 files changed, 1013 insertions(+), 9 deletions(-) create mode 100644 lib/ldb/tests/ldb_filter_attrs_test.c diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c index 9d87a10b9f1..1d67622b69e 100644 --- a/lib/ldb/common/ldb_pack.c +++ b/lib/ldb/common/ldb_pack.c @@ -1163,7 +1163,10 @@ int ldb_filter_attrs(struct ldb_context *ldb, } else if (i == 0) { return 0; - /* Otherwise we are copying at most as many element as we have attributes */ + /* + * Otherwise we are copying at most as many elements as we + * have attributes + */ } else { elements_size = i; } @@ -1177,7 +1180,12 @@ int ldb_filter_attrs(struct ldb_context *ldb, for (i = 0; i < msg->num_elements; i++) { struct ldb_message_element *el = &msg->elements[i]; - struct ldb_message_element *el2 = &filtered_msg->elements[num_elements]; + + /* + * el2 is assigned after the Pigeonhole principle + * check below for clarity + */ + struct ldb_message_element *el2 = NULL; unsigned int j; if (keep_all == false) { @@ -1193,6 +1201,18 @@ int ldb_filter_attrs(struct ldb_context *ldb, continue; } } + + /* + * Pigeonhole principle: we can't have more elements + * than the number of attributes if they are unique in + * the DB. + */ + if (num_elements >= elements_size) { + goto failed; + } + + el2 = &filtered_msg->elements[num_elements]; + *el2 = *el; el2->name = talloc_strdup(filtered_msg->elements, el->name); @@ -1211,13 +1231,6 @@ int ldb_filter_attrs(struct ldb_context *ldb, } } num_elements++; - - /* Pidginhole principle: we can't have more elements - * than the number of attributes if they are unique in - * the DB */ - if (num_elements > elements_size) { - goto failed; - } } filtered_msg->num_elements = num_elements; diff --git a/lib/ldb/tests/ldb_filter_attrs_test.c b/lib/ldb/tests/ldb_filter_attrs_test.c new file mode 100644 index 00000000000..d04775879ac --- /dev/null +++ b/lib/ldb/tests/ldb_filter_attrs_test.c @@ -0,0 +1,986 @@ +/* + * Tests exercising the ldb_filter_attrs(). + * + * + * Copyright (C) Catalyst.NET Ltd 2017 + * Copyright (C) Andrew Bartlett 2019 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/* + * from cmocka.c: + * These headers or their equivalents should be included prior to + * including + * this header file. + * + * #include + * #include + * #include + * + * This allows test applications to use custom definitions of C standard + * library functions and types. + */ +#include +#include +#include +#include +#include + +#include "../include/ldb.h" +#include "../include/ldb_module.h" + +struct ldbtest_ctx { + struct tevent_context *ev; + struct ldb_context *ldb; +}; + +/* + * NOTE WELL: + * + * This test checks the current behaviour of the function, however + * this is not in a public ABI and many of the tested behaviours are + * not ideal. If the behaviour is deliberatly improved, this test + * should be updated without worry to the new better behaviour. + * + * In particular the test is particularly to ensure the current + * behaviour is memory-safe. + */ + +static int setup(void **state) +{ + struct ldbtest_ctx *test_ctx; + + test_ctx = talloc_zero(NULL, struct ldbtest_ctx); + assert_non_null(test_ctx); + + test_ctx->ev = tevent_context_init(test_ctx); + assert_non_null(test_ctx->ev); + + test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev); + assert_non_null(test_ctx->ldb); + + *state = test_ctx; + return 0; +} + +static int teardown(void **state) +{ + talloc_free(*state); + return 0; +} + + +/* + * Test against a record with only one attribute, matching the one in + * the list + */ +static void test_filter_attrs_one_attr_matched(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"foo", NULL}; + + uint8_t value[] = "The value.......end"; + struct ldb_val value_1 = { + .data = value, + .length = (sizeof(value)) + }; + struct ldb_message_element element_1 = { + .name = "foo", + .num_values = 1, + .values = &value_1 + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 1, + .elements = &element_1, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + + /* + * assert the ldb_filter_attrs does not read or modify + * filtered_msg.dn in this case + */ + assert_null(filtered_msg->dn); + assert_int_equal(filtered_msg->num_elements, 1); + assert_string_equal(filtered_msg->elements[0].name, "foo"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, + sizeof(value)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, + value, sizeof(value)); +} + +/* + * Test against a record with only one attribute, matching the one of + * the multiple attributes in the list + */ +static void test_filter_attrs_one_attr_matched_of_many(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"foo", "bar", "baz", NULL}; + + uint8_t value[] = "The value.......end"; + struct ldb_val value_1 = { + .data = value, + .length = (sizeof(value)) + }; + struct ldb_message_element element_1 = { + .name = "foo", + .num_values = 1, + .values = &value_1 + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 1, + .elements = &element_1, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + + /* + * assert the ldb_filter_attrs does not read or modify + * filtered_msg.dn in this case + */ + assert_null(filtered_msg->dn); + assert_int_equal(filtered_msg->num_elements, 1); + assert_string_equal(filtered_msg->elements[0].name, "foo"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, + sizeof(value)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, + value, sizeof(value)); +} + +/* + * Test against a record with only one attribute, matching both + * attributes in the list + */ +static void test_filter_attrs_two_attr_matched_attrs(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + /* deliberatly the other order */ + const char *attrs[] = {"bar", "foo", NULL}; + + uint8_t value1[] = "The value.......end"; + uint8_t value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { + .data = value1, + .length = (sizeof(value1)) + }; + struct ldb_val value_2 = { + .data = value2, + .length = (sizeof(value2)) + }; + + /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "foo", + .num_values = 1, + .values = &value_1 + }, + { + .name = "bar", + .num_values = 1, + .values = &value_2 + } + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 2, + .elements = elements, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + assert_int_equal(filtered_msg->num_elements, 2); + + /* + * assert the ldb_filter_attrs does not read or modify + * filtered_msg.dn in this case + */ + assert_null(filtered_msg->dn); + + /* Assert that DB order is preserved */ + assert_string_equal(filtered_msg->elements[0].name, "foo"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, + sizeof(value1)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, + value1, sizeof(value1)); + assert_string_equal(filtered_msg->elements[1].name, "bar"); + assert_int_equal(filtered_msg->elements[1].num_values, 1); + assert_int_equal(filtered_msg->elements[1].values[0].length, + sizeof(value2)); + assert_memory_equal(filtered_msg->elements[1].values[0].data, + value2, sizeof(value2)); +} + +/* + * Test against a record with two attributes, only of which is in + * the list + */ +static void test_filter_attrs_two_attr_matched_one_attr(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + /* deliberatly the other order */ + const char *attrs[] = {"bar", NULL}; + + uint8_t value1[] = "The value.......end"; + uint8_t value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { + .data = value1, + .length = (sizeof(value1)) + }; + struct ldb_val value_2 = { + .data = value2, + .length = (sizeof(value2)) + }; + + /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "foo", + .num_values = 1, + .values = &value_1 + }, + { + .name = "bar", + .num_values = 1, + .values = &value_2 + } + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 2, + .elements = elements, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + assert_int_equal(filtered_msg->num_elements, 1); + + /* + * assert the ldb_filter_attrs does not read or modify + * filtered_msg.dn in this case + */ + assert_null(filtered_msg->dn); + + /* Assert that DB order is preserved */ + assert_string_equal(filtered_msg->elements[0].name, "bar"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, + sizeof(value2)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, + value2, sizeof(value2)); +} + +/* + * Test against a record with two attributes, both matching the one + * specified attribute in the list (a corrupt record) + */ +static void test_filter_attrs_two_dup_attr_matched_one_attr(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + /* deliberatly the other order */ + const char *attrs[] = {"bar", NULL}; + + uint8_t value1[] = "The value.......end"; + uint8_t value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { + .data = value1, + .length = (sizeof(value1)) + }; + struct ldb_val value_2 = { + .data = value2, + .length = (sizeof(value2)) + }; + + /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "bar", + .num_values = 1, + .values = &value_1 + }, + { + .name = "bar", + .num_values = 1, + .values = &value_2 + } + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 2, + .elements = elements, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + + /* This should fail the pidgenhole test */ + assert_int_equal(ret, -1); +} + +/* + * Test against a record with two attributes, both matching the one + * specified attribute in the list (a corrupt record) + */ +static void test_filter_attrs_two_dup_attr_matched_dup(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"bar", "bar", NULL}; + + uint8_t value1[] = "The value.......end"; + uint8_t value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { + .data = value1, + .length = (sizeof(value1)) + }; + struct ldb_val value_2 = { + .data = value2, + .length = (sizeof(value2)) + }; + + /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "bar", + .num_values = 1, + .values = &value_1 + }, + { + .name = "bar", + .num_values = 1, + .values = &value_2 + } + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 2, + .elements = elements, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + + /* This does not fail the pidgenhole test */ + assert_int_equal(ret, LDB_SUCCESS); + assert_int_equal(filtered_msg->num_elements, 2); + + /* Assert that DB order is preserved */ + assert_string_equal(filtered_msg->elements[0].name, "bar"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, + sizeof(value1)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, + value1, sizeof(value1)); + assert_string_equal(filtered_msg->elements[1].name, "bar"); + assert_int_equal(filtered_msg->elements[1].num_values, 1); + assert_int_equal(filtered_msg->elements[1].values[0].length, + sizeof(value2)); + assert_memory_equal(filtered_msg->elements[1].values[0].data, + value2, sizeof(value2)); +} + +/* + * Test against a record with two attributes, both matching one of the + * specified attributes in the list (a corrupt record) + */ +static void test_filter_attrs_two_dup_attr_matched_one_of_two(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"bar", "foo", NULL}; + + uint8_t value1[] = "The value.......end"; + uint8_t value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { + .data = value1, + .length = (sizeof(value1)) + }; + struct ldb_val value_2 = { + .data = value2, + .length = (sizeof(value2)) + }; + + /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "bar", + .num_values = 1, + .values = &value_1 + }, + { + .name = "bar", + .num_values = 1, + .values = &value_2 + } + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 2, + .elements = elements, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + + /* This does not fail the pidgenhole test */ + assert_int_equal(ret, LDB_SUCCESS); + assert_int_equal(filtered_msg->num_elements, 2); + + /* Assert that DB order is preserved */ + assert_string_equal(filtered_msg->elements[0].name, "bar"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, + sizeof(value1)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, + value1, sizeof(value1)); + assert_string_equal(filtered_msg->elements[1].name, "bar"); + assert_int_equal(filtered_msg->elements[1].num_values, 1); + assert_int_equal(filtered_msg->elements[1].values[0].length, + sizeof(value2)); + assert_memory_equal(filtered_msg->elements[1].values[0].data, + value2, sizeof(value2)); +} + +/* + * Test against a record with two attributes against * (but not the + * other named attribute) (a corrupt record) + */ +static void test_filter_attrs_two_dup_attr_matched_star(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", "foo", NULL}; + + uint8_t value1[] = "The value.......end"; + uint8_t value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { + .data = value1, + .length = (sizeof(value1)) + }; + struct ldb_val value_2 = { + .data = value2, + .length = (sizeof(value2)) + }; + + /* foo and bar are the other order to in attrs */ + struct ldb_message_element elements[] = { + { + .name = "bar", + .num_values = 1, + .values = &value_1 + }, + { + .name = "bar", + .num_values = 1, + .values = &value_2 + } + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 2, + .elements = elements, + }; + + assert_non_null(in.dn); + + /* Needed as * implies distinguishedName */ + filtered_msg->dn = in.dn; + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + + /* This does not fail the pidgenhole test */ + assert_int_equal(ret, LDB_SUCCESS); + assert_int_equal(filtered_msg->num_elements, 3); + + /* Assert that DB order is preserved */ + assert_string_equal(filtered_msg->elements[0].name, "bar"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_int_equal(filtered_msg->elements[0].values[0].length, + sizeof(value1)); + assert_memory_equal(filtered_msg->elements[0].values[0].data, + value1, sizeof(value1)); + assert_string_equal(filtered_msg->elements[1].name, "bar"); + assert_int_equal(filtered_msg->elements[1].num_values, 1); + assert_int_equal(filtered_msg->elements[1].values[0].length, + sizeof(value2)); + assert_memory_equal(filtered_msg->elements[1].values[0].data, + value2, sizeof(value2)); + /* + * assert the ldb_filter_attrs does not modify filtered_msg.dn + * in this case + */ + assert_ptr_equal(filtered_msg->dn, in.dn); + assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, + "distinguishedName", + NULL), + ldb_dn_get_linearized(in.dn)); +} + +/* + * Test against a record with only one attribute, matching the * in + * the list + */ +static void test_filter_attrs_one_attr_matched_star(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", NULL}; + + uint8_t value[] = "The value.......end"; + struct ldb_val value_1 = { + .data = value, + .length = (sizeof(value)) + }; + struct ldb_message_element element_1 = { + .name = "foo", + .num_values = 1, + .values = &value_1 + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 1, + .elements = &element_1, + }; + + assert_non_null(in.dn); + + /* Needed as * implies distinguishedName */ + filtered_msg->dn = in.dn; + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + assert_int_equal(filtered_msg->num_elements, 2); + + /* + * assert the ldb_filter_attrs does not modify filtered_msg.dn + * in this case + */ + assert_ptr_equal(filtered_msg->dn, in.dn); + assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, + "distinguishedName", + NULL), + ldb_dn_get_linearized(in.dn)); + assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, + "foo", + NULL), + value); +} + +/* + * Test against a record with two attributes, matching the * in + * the list + */ +static void test_filter_attrs_two_attr_matched_star(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", NULL}; + + uint8_t value1[] = "The value.......end"; + uint8_t value2[] = "The value..MUST.end"; + struct ldb_val value_1 = { + .data = value1, + .length = (sizeof(value1)) + }; + struct ldb_val value_2 = { + .data = value2, + .length = (sizeof(value2)) + }; + struct ldb_message_element elements[] = { + { + .name = "foo", + .num_values = 1, + .values = &value_1 + }, + { + .name = "bar", + .num_values = 1, + .values = &value_2 + } + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 2, + .elements = elements, + }; + + assert_non_null(in.dn); + + /* Needed as * implies distinguishedName */ + filtered_msg->dn = in.dn; + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + assert_int_equal(filtered_msg->num_elements, 3); + + /* + * assert the ldb_filter_attrs does not modify filtered_msg.dn + * in this case + */ + assert_ptr_equal(filtered_msg->dn, in.dn); + assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, + "distinguishedName", + NULL), + ldb_dn_get_linearized(in.dn)); + assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, + "foo", + NULL), + value1); + assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, + "bar", + NULL), + value2); +} + +/* + * Test against a record with only one attribute, matching the * in + * the list, but without the DN being pre-filled. Fails due to need + * to contstruct the distinguishedName + */ +static void test_filter_attrs_one_attr_matched_star_no_dn(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", NULL}; + + uint8_t value[] = "The value.......end"; + struct ldb_val value_1 = { + .data = value, + .length = (sizeof(value)) + }; + struct ldb_message_element element_1 = { + .name = "foo", + .num_values = 1, + .values = &value_1 + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 1, + .elements = &element_1, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, -1); +} + +/* + * Test against a record with only one attribute, matching the * in + * the list plus requsesting distinguishedName + */ +static void test_filter_attrs_one_attr_matched_star_dn(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"*", "distinguishedName", NULL}; + + uint8_t value[] = "The value.......end"; + struct ldb_val value_1 = { + .data = value, + .length = (sizeof(value)) + }; + struct ldb_message_element element_1 = { + .name = "foo", + .num_values = 1, + .values = &value_1 + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 1, + .elements = &element_1, + }; + + assert_non_null(in.dn); + + /* Needed for distinguishedName */ + filtered_msg->dn = in.dn; + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + assert_int_equal(filtered_msg->num_elements, 2); + + /* show that ldb_filter_attrs does not modify in.dn */ + assert_ptr_equal(filtered_msg->dn, in.dn); + + assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, + "distinguishedName", + NULL), + ldb_dn_get_linearized(in.dn)); + assert_string_equal(ldb_msg_find_attr_as_string(filtered_msg, + "foo", + NULL), + value); +} + +/* + * Test against a record with only one attribute, but returning + * distinguishedName from the list (only) + */ +static void test_filter_attrs_one_attr_matched_dn(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {"distinguishedName", NULL}; + + uint8_t value[] = "The value.......end"; + struct ldb_val value_1 = { + .data = value, + .length = (sizeof(value)) + }; + struct ldb_message_element element_1 = { + .name = "foo", + .num_values = 1, + .values = &value_1 + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 1, + .elements = &element_1, + }; + + assert_non_null(in.dn); + + /* Needed for distinguishedName */ + filtered_msg->dn = in.dn; + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + assert_int_equal(filtered_msg->num_elements, 1); + + /* show that ldb_filter_attrs does not modify in.dn */ + assert_ptr_equal(filtered_msg->dn, in.dn); + assert_string_equal(filtered_msg->elements[0].name, "distinguishedName"); + assert_int_equal(filtered_msg->elements[0].num_values, 1); + assert_string_equal(filtered_msg->elements[0].values[0].data, + ldb_dn_get_linearized(in.dn)); +} + +/* + * Test against a record with only one attribute, not matching the + * empty attribute list + */ +static void test_filter_attrs_one_attr_empty_list(void **state) +{ + struct ldbtest_ctx *ctx = *state; + int ret; + + struct ldb_message *filtered_msg = ldb_msg_new(ctx); + + const char *attrs[] = {NULL}; + + uint8_t value[] = "The value.......end"; + struct ldb_val value_1 = { + .data = value, + .length = (sizeof(value)) + }; + struct ldb_message_element element_1 = { + .name = "foo", + .num_values = 1, + .values = &value_1 + }; + struct ldb_message in = { + .dn = ldb_dn_new(ctx, ctx->ldb, "dc=samba,dc=org"), + .num_elements = 1, + .elements = &element_1, + }; + + assert_non_null(in.dn); + + ret = ldb_filter_attrs(ctx->ldb, + &in, + attrs, + filtered_msg); + assert_int_equal(ret, LDB_SUCCESS); + assert_non_null(filtered_msg); + assert_int_equal(filtered_msg->num_elements, 0); + assert_null(filtered_msg->dn); + assert_null(filtered_msg->elements); +} + +int main(int argc, const char **argv) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown( + test_filter_attrs_one_attr_matched, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_one_attr_matched_of_many, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_two_attr_matched_attrs, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_two_attr_matched_one_attr, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_two_dup_attr_matched_one_attr, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_two_dup_attr_matched_dup, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_two_dup_attr_matched_one_of_two, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_two_dup_attr_matched_star, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_one_attr_matched_star, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_two_attr_matched_star, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_one_attr_matched_star_no_dn, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_one_attr_matched_star_dn, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_one_attr_matched_dn, + setup, + teardown), + cmocka_unit_test_setup_teardown( + test_filter_attrs_one_attr_empty_list, + setup, + teardown), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/lib/ldb/wscript b/lib/ldb/wscript index a63a6c2171f..f928e2c739c 100644 --- a/lib/ldb/wscript +++ b/lib/ldb/wscript @@ -512,6 +512,11 @@ def build(bld): deps='cmocka ldb ldb_tdb_err_map', install=False) + bld.SAMBA_BINARY('ldb_filter_attrs_test', + source='tests/ldb_filter_attrs_test.c', + deps='cmocka ldb ldb_tdb_err_map', + install=False) + bld.SAMBA_BINARY('ldb_key_value_sub_txn_tdb_test', bld.SUBDIR('ldb_key_value', '''ldb_kv_search.c -- 2.17.1 From 11427be15ed6701fb2a15830846b57fe5e62fb42 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 26 Aug 2019 14:48:52 +1200 Subject: [PATCH 124/376] ldb: use TALLOC_FREE() over talloc_free() in ldb_filter_attrs() This is a macro that sets the pointer to NULL after the talloc_free() and is part of our standard coding practices. Signed-off-by: Andrew Bartlett Reviewed-by: Gary Lockyer (cherry picked from commit 2117789c35fbf6d0ed02f391f17593e11727ec3e) --- lib/ldb/common/ldb_pack.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c index 1d67622b69e..b5e1fbbc4ff 100644 --- a/lib/ldb/common/ldb_pack.c +++ b/lib/ldb/common/ldb_pack.c @@ -1251,8 +1251,7 @@ int ldb_filter_attrs(struct ldb_context *ldb, goto failed; } } else { - talloc_free(filtered_msg->elements); - filtered_msg->elements = NULL; + TALLOC_FREE(filtered_msg->elements); } return 0; -- 2.17.1 From 61a039cc21d845bb4b984929d878dd8cf68839fe Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 26 Aug 2019 14:50:15 +1200 Subject: [PATCH 125/376] ldb: Call TALLOC_FREE(filtered_msg->elements) on ldb_filter_attrs() failure Signed-off-by: Andrew Bartlett Reviewed-by: Gary Lockyer Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Aug 27 01:16:33 UTC 2019 on sn-devel-184 (cherry picked from commit 1521a22f4366c86ec955cb9d32b7a758315d8ce0) --- lib/ldb/common/ldb_pack.c | 1 + lib/ldb/tests/ldb_filter_attrs_test.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c index b5e1fbbc4ff..e7dd364008a 100644 --- a/lib/ldb/common/ldb_pack.c +++ b/lib/ldb/common/ldb_pack.c @@ -1256,5 +1256,6 @@ int ldb_filter_attrs(struct ldb_context *ldb, return 0; failed: + TALLOC_FREE(filtered_msg->elements); return -1; } diff --git a/lib/ldb/tests/ldb_filter_attrs_test.c b/lib/ldb/tests/ldb_filter_attrs_test.c index d04775879ac..7d555e0da2e 100644 --- a/lib/ldb/tests/ldb_filter_attrs_test.c +++ b/lib/ldb/tests/ldb_filter_attrs_test.c @@ -384,6 +384,7 @@ static void test_filter_attrs_two_dup_attr_matched_one_attr(void **state) /* This should fail the pidgenhole test */ assert_int_equal(ret, -1); + assert_null(filtered_msg->elements); } /* @@ -772,6 +773,7 @@ static void test_filter_attrs_one_attr_matched_star_no_dn(void **state) attrs, filtered_msg); assert_int_equal(ret, -1); + assert_null(filtered_msg->elements); } /* -- 2.17.1 From c71c51dda004a617eaeccb0819b70310de1ebd14 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Fri, 26 Jul 2019 09:49:13 +1200 Subject: [PATCH 126/376] ldb: don't try to save a value that isn't there BUG: https://bugzilla.samba.org/show_bug.cgi?id=14049 Signed-off-by: Douglas Bagnall Reviewed-by: Andrew Bartlett Reviewed-by: Gary Lockyer (cherry picked from commit 54f30f2fe3f03c9640664f9a11260b093fc57a5b) --- lib/ldb/common/ldb_dn.c | 47 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c index 9b2fa966e11..a7fb0d9c443 100644 --- a/lib/ldb/common/ldb_dn.c +++ b/lib/ldb/common/ldb_dn.c @@ -697,31 +697,32 @@ static bool ldb_dn_explode(struct ldb_dn *dn) goto failed; } - /* save last element */ - if ( t ) { - /* trim back */ - d -= (p - t); - l -= (p - t); - } + if (in_value) { + /* save last element */ + if ( t ) { + /* trim back */ + d -= (p - t); + l -= (p - t); + } + + *d++ = '\0'; + /* + * This talloc_memdup() is OK with the + * +1 because *d has been set to '\0' + * just above. + */ + dn->components[dn->comp_num].value.length = l; + dn->components[dn->comp_num].value.data = + (uint8_t *)talloc_memdup(dn->components, dt, l + 1); + if ( ! dn->components[dn->comp_num].value.data) { + /* ouch */ + goto failed; + } + talloc_set_name_const(dn->components[dn->comp_num].value.data, + (const char *)dn->components[dn->comp_num].value.data); - *d++ = '\0'; - /* - * This talloc_memdup() is OK with the - * +1 because *d has been set to '\0' - * just above. - */ - dn->components[dn->comp_num].value.length = l; - dn->components[dn->comp_num].value.data = - (uint8_t *)talloc_memdup(dn->components, dt, l + 1); - if ( ! dn->components[dn->comp_num].value.data) { - /* ouch */ - goto failed; + dn->comp_num++; } - talloc_set_name_const(dn->components[dn->comp_num].value.data, - (const char *)dn->components[dn->comp_num].value.data); - - dn->comp_num++; - talloc_free(data); return true; -- 2.17.1 From 0f993c094ea242934766761389cecd5ecfd14a37 Mon Sep 17 00:00:00 2001 From: Douglas Bagnall Date: Thu, 25 Jul 2019 12:09:16 +1200 Subject: [PATCH 127/376] ldb: add some dn explode tests BUG: https://bugzilla.samba.org/show_bug.cgi?id=14049 Signed-off-by: Douglas Bagnall Reviewed-by: Andrew Bartlett Reviewed-by: Gary Lockyer (cherry picked from commit a097ddf65ce56dcd2e0b072b6dd78f512a77a9da) --- lib/ldb/tests/test_ldb_dn.c | 70 +++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/lib/ldb/tests/test_ldb_dn.c b/lib/ldb/tests/test_ldb_dn.c index 4965dcef575..7c202399a21 100644 --- a/lib/ldb/tests/test_ldb_dn.c +++ b/lib/ldb/tests/test_ldb_dn.c @@ -23,6 +23,7 @@ #include #include +#include "ldb_private.h" static void test_ldb_dn_add_child_fmt(void **state) { @@ -105,12 +106,81 @@ static void test_ldb_dn_add_child_val2(void **state) } +struct explode_test { + const char *strdn; + int comp_num; + int ext_comp_num; + bool special; + bool invalid; + const char *linearized; + const char *ext_linearized; + bool explode_result; +}; + +static void test_ldb_dn_explode(void **state) +{ + size_t i; + struct ldb_context *ldb = ldb_init(NULL, NULL); + struct explode_test tests[] = { + {"A=B", 1, 0, false, false, "A=B", "A=B", true}, + {"", 0, 0, false, false, "", "", true}, + {" ", -1, -1, false, false, " ", " ", false}, + {"<>", 0, 0, false, false, "", NULL, true}, + {"<", 0, 0, false, false, "", NULL, true}, + {"<><", 0, 0, false, false, "", NULL, true}, + {"<><>", 0, 0, false, false, "", NULL, true}, + {"A=B,C=D", 2, 0, false, false, "A=B,C=D", "A=B,C=D", true}, + {"x=🔥", 1, 0, false, false, "x=🔥", "x=🔥", true}, + }; + + + for (i = 0; i < ARRAY_SIZE(tests); i++) { + bool result; + const char *linear; + const char *ext_linear; + struct ldb_dn *dn = ldb_dn_new(ldb, ldb, tests[i].strdn); + + /* + * special, invalid, linear, and ext_linear are set before + * explode + */ + fprintf(stderr, "%zu «%s»: ", i, tests[i].strdn); + linear = ldb_dn_get_linearized(dn); + assert_true((linear == NULL) == (tests[i].linearized == NULL)); + assert_string_equal(linear, + tests[i].linearized); + + ext_linear = ldb_dn_get_extended_linearized(ldb, dn, 1); + assert_true((ext_linear == NULL) == + (tests[i].ext_linearized == NULL)); + + if (tests[i].ext_linearized != NULL) { + assert_string_equal(ext_linear, + tests[i].ext_linearized); + } + assert_true(ldb_dn_is_special(dn) == tests[i].special); + assert_true(ldb_dn_is_valid(dn) != tests[i].invalid); + + /* comp nums are set by explode */ + result = ldb_dn_validate(dn); + fprintf(stderr, "res %i lin «%s» ext «%s»\n", + result, linear, ext_linear); + + assert_true(result == tests[i].explode_result); + assert_int_equal(ldb_dn_get_comp_num(dn), + tests[i].comp_num); + assert_int_equal(ldb_dn_get_extended_comp_num(dn), + tests[i].ext_comp_num); + } +} + int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_ldb_dn_add_child_fmt), cmocka_unit_test(test_ldb_dn_add_child_fmt2), cmocka_unit_test(test_ldb_dn_add_child_val), cmocka_unit_test(test_ldb_dn_add_child_val2), + cmocka_unit_test(test_ldb_dn_explode), }; return cmocka_run_group_tests(tests, NULL, NULL); -- 2.17.1 From 1bc9476be79b994a3a9b0618f23f176e399c5aaa Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 22 Aug 2019 10:59:07 +1200 Subject: [PATCH 128/376] ldb: Rework all pointer NULL tests to use Samba's normal style Also avoid if () without braces BUG: https://bugzilla.samba.org/show_bug.cgi?id=14049 Signed-off-by: Andrew Bartlett Reviewed-by: Gary Lockyer (cherry picked from commit 3f290e95c2c133eb2c983ecc984d3dff4809f3d3) --- lib/ldb/common/ldb_dn.c | 52 ++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c index a7fb0d9c443..377dd74d9f3 100644 --- a/lib/ldb/common/ldb_dn.c +++ b/lib/ldb/common/ldb_dn.c @@ -298,19 +298,21 @@ static bool ldb_dn_explode(struct ldb_dn *dn) char *parse_dn; bool is_index; - if ( ! dn || dn->invalid) return false; + if (dn == NULL || dn->invalid) { + return false; + } - if (dn->components) { + if (dn->components != NULL) { return true; } - if (dn->ext_linearized) { + if (dn->ext_linearized != NULL) { parse_dn = dn->ext_linearized; } else { parse_dn = dn->linearized; } - if ( ! parse_dn ) { + if (parse_dn == NULL) { return false; } @@ -333,13 +335,13 @@ static bool ldb_dn_explode(struct ldb_dn *dn) /* in the common case we have 3 or more components */ /* make sure all components are zeroed, other functions depend on it */ dn->components = talloc_zero_array(dn, struct ldb_dn_component, 3); - if ( ! dn->components) { + if (dn->components == NULL) { return false; } /* Components data space is allocated here once */ data = talloc_array(dn->components, char, strlen(parse_dn) + 1); - if (!data) { + if (data == NULL) { goto failed; } @@ -403,7 +405,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) dn->ext_components = ext_comp; ext_syntax = ldb_dn_extended_syntax_by_name(dn->ldb, ex_name); - if (!ext_syntax) { + if (ext_syntax == NULL) { /* We don't know about this type of extended DN */ goto failed; } @@ -486,7 +488,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) * with spaces trimmed) */ *d++ = '\0'; dn->components[dn->comp_num].name = talloc_strdup(dn->components, dt); - if ( ! dn->components[dn->comp_num].name) { + if (dn->components[dn->comp_num].name == NULL) { /* ouch */ goto failed; } @@ -564,7 +566,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) } /* ok found value terminator */ - if ( t ) { + if (t != NULL) { /* trim back */ d -= (p - t); l -= (p - t); @@ -585,7 +587,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) dn->components[dn->comp_num].value.data = \ (uint8_t *)talloc_memdup(dn->components, dt, l + 1); dn->components[dn->comp_num].value.length = l; - if ( ! dn->components[dn->comp_num].value.data) { + if (dn->components[dn->comp_num].value.data == NULL) { /* ouch ! */ goto failed; } @@ -600,7 +602,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) dn->components, struct ldb_dn_component, dn->comp_num + 1); - if ( ! dn->components) { + if (dn->components == NULL) { /* ouch ! */ goto failed; } @@ -618,7 +620,9 @@ static bool ldb_dn_explode(struct ldb_dn *dn) values, which contain a '+' or '=' which should normally be escaped */ if (is_index) { - if ( t ) t = NULL; + if (t != NULL) { + t = NULL; + } *d++ = *p++; l++; break; @@ -639,7 +643,9 @@ static bool ldb_dn_explode(struct ldb_dn *dn) *d++ = *p++; l++; - if ( t ) t = NULL; + if (t != NULL) { + t = NULL; + } break; case '\\': @@ -653,7 +659,9 @@ static bool ldb_dn_explode(struct ldb_dn *dn) *d++ = *p++; l++; - if ( t ) t = NULL; + if (t != NULL) { + t = NULL; + } break; default: @@ -672,14 +680,20 @@ static bool ldb_dn_explode(struct ldb_dn *dn) escape = false; l++; - if ( t ) t = NULL; + if (t != NULL) { + t = NULL; + } break; } if (*p == ' ') { - if ( ! t) t = p; + if (t == NULL) { + t = p; + } } else { - if ( t ) t = NULL; + if (t != NULL) { + t = NULL; + } } *d++ = *p++; @@ -699,7 +713,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) if (in_value) { /* save last element */ - if ( t ) { + if (t != NULL) { /* trim back */ d -= (p - t); l -= (p - t); @@ -714,7 +728,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) dn->components[dn->comp_num].value.length = l; dn->components[dn->comp_num].value.data = (uint8_t *)talloc_memdup(dn->components, dt, l + 1); - if ( ! dn->components[dn->comp_num].value.data) { + if (dn->components[dn->comp_num].value.data == NULL) { /* ouch */ goto failed; } -- 2.17.1 From 9b0c30517834da57a436ac6a0bad1fa2c6173849 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 22 Aug 2019 11:09:55 +1200 Subject: [PATCH 129/376] ldb: Add test with == true or false to boolean if statements in ldb_dn_explode() This is beyond the normal level of clarity we expect in Samba, and is of course rudundent, but this is a complex routine that has confusing tests, some of pointers and some of boolean state values. This tries to make the code as clear as possible pending a more comprehensive rewrite. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14049 Signed-off-by: Andrew Bartlett Reviewed-by: Gary Lockyer (cherry picked from commit 52bd2dde5ae809ecc115f7087e367327f4771e73) --- lib/ldb/common/ldb_dn.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c index 377dd74d9f3..b9a414dc566 100644 --- a/lib/ldb/common/ldb_dn.c +++ b/lib/ldb/common/ldb_dn.c @@ -298,7 +298,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) char *parse_dn; bool is_index; - if (dn == NULL || dn->invalid) { + if (dn == NULL || dn->invalid == true) { return false; } @@ -324,7 +324,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) } /* Special DNs case */ - if (dn->special) { + if (dn->special == true) { return true; } @@ -350,7 +350,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) d = dt = data; while (*p) { - if (in_extended) { + if (in_extended == true) { if (!in_ex_name && !in_ex_value) { @@ -437,8 +437,8 @@ static bool ldb_dn_explode(struct ldb_dn *dn) *d++ = *p++; continue; } - if (in_attr) { - if (trim) { + if (in_attr == true) { + if (trim == true) { if (*p == ' ') { p++; continue; @@ -505,7 +505,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) goto failed; } - if (is_oid && ( ! (isdigit(*p) || (*p == '.')))) { + if (is_oid == true && ( ! (isdigit(*p) || (*p == '.')))) { /* not a digit nor a dot, * invalid attribute oid */ ldb_dn_mark_invalid(dn); @@ -521,8 +521,8 @@ static bool ldb_dn_explode(struct ldb_dn *dn) continue; } - if (in_value) { - if (in_quote) { + if (in_value == true) { + if (in_quote == true) { if (*p == '\"') { if (p[-1] != '\\') { p++; @@ -535,7 +535,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) continue; } - if (trim) { + if (trim == true) { if (*p == ' ') { p++; continue; @@ -558,7 +558,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) */ case ',': - if (escape) { + if (escape == true) { *d++ = *p++; l++; escape = false; @@ -619,7 +619,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) accept the base64 encoded binary index values, which contain a '+' or '=' which should normally be escaped */ - if (is_index) { + if (is_index == true) { if (t != NULL) { t = NULL; } @@ -634,7 +634,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) case '>': case ';': /* a string with not escaped specials is invalid (tested) */ - if ( ! escape) { + if (escape == false) { ldb_dn_mark_invalid(dn); goto failed; } @@ -649,7 +649,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) break; case '\\': - if ( ! escape) { + if (escape == false) { escape = true; p++; continue; @@ -665,7 +665,7 @@ static bool ldb_dn_explode(struct ldb_dn *dn) break; default: - if (escape) { + if (escape == true) { if (isxdigit(p[0]) && isxdigit(p[1])) { if (sscanf(p, "%02x", &x) != 1) { /* invalid escaping sequence */ @@ -705,13 +705,13 @@ static bool ldb_dn_explode(struct ldb_dn *dn) } } - if (in_attr || in_quote) { + if (in_attr == true || in_quote == true) { /* invalid dn */ ldb_dn_mark_invalid(dn); goto failed; } - if (in_value) { + if (in_value == true) { /* save last element */ if (t != NULL) { /* trim back */ -- 2.17.1 From e019f3a6aac62460ee9768fec4001e00f00f8096 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 27 Aug 2019 13:16:18 +1200 Subject: [PATCH 130/376] ldb: Do not read beyond the end of the extended DN component when printing The print functions used in Samba NULL terminate, but do not assume they will BUG: https://bugzilla.samba.org/show_bug.cgi?id=14049 Signed-off-by: Andrew Bartlett Reviewed-by: Gary Lockyer (cherry picked from commit a8a3cef3a768aaff01227dd7b229fb7b3aef926f) --- lib/ldb/common/ldb_dn.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/ldb/common/ldb_dn.c b/lib/ldb/common/ldb_dn.c index b9a414dc566..83f94e3b913 100644 --- a/lib/ldb/common/ldb_dn.c +++ b/lib/ldb/common/ldb_dn.c @@ -871,11 +871,15 @@ char *ldb_dn_get_extended_linearized(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, int } if (i == 0) { - p = talloc_asprintf(mem_ctx, "<%s=%s>", - name, val.data); + p = talloc_asprintf(mem_ctx, "<%s=%.*s>", + name, + (int)val.length, + val.data); } else { - p = talloc_asprintf_append_buffer(p, ";<%s=%s>", - name, val.data); + p = talloc_asprintf_append_buffer(p, ";<%s=%.*s>", + name, + (int)val.length, + val.data); } talloc_free(val.data); -- 2.17.1 From 9392ee7d29081118afd2dfd531946cbdcaba729d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 27 Aug 2019 13:16:50 +1200 Subject: [PATCH 131/376] ldb: Extend the ldb_dn_explode test matrix BUG: https://bugzilla.samba.org/show_bug.cgi?id=14049 Signed-off-by: Andrew Bartlett Reviewed-by: Gary Lockyer (cherry picked from commit 10058bcfa16d5029e61252d64d142a8aab9ec296) --- lib/ldb/tests/test_ldb_dn.c | 53 ++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/lib/ldb/tests/test_ldb_dn.c b/lib/ldb/tests/test_ldb_dn.c index 7c202399a21..05f30e4ac67 100644 --- a/lib/ldb/tests/test_ldb_dn.c +++ b/lib/ldb/tests/test_ldb_dn.c @@ -113,10 +113,42 @@ struct explode_test { bool special; bool invalid; const char *linearized; - const char *ext_linearized; + const char *ext_linearized_1; bool explode_result; }; +static int extended_dn_read_ID(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + + /* Allow to check we can cope with validity checks */ + if (in->length != 4) { + return -1; + } + + *out = *in; + out->data = talloc_memdup(mem_ctx, in->data, in->length); + if (out->data == NULL) { + return -1; + } + + return 0; +} + +/* write out (resued for both HEX and clear for now) */ +static int extended_dn_write_ID(struct ldb_context *ldb, void *mem_ctx, + const struct ldb_val *in, struct ldb_val *out) +{ + *out = *in; + + out->data = talloc_memdup(mem_ctx, in->data, in->length); + if (out->data == NULL) { + return -1; + } + return 0; +} + + static void test_ldb_dn_explode(void **state) { size_t i; @@ -130,9 +162,22 @@ static void test_ldb_dn_explode(void **state) {"<><", 0, 0, false, false, "", NULL, true}, {"<><>", 0, 0, false, false, "", NULL, true}, {"A=B,C=D", 2, 0, false, false, "A=B,C=D", "A=B,C=D", true}, + {"A=B,C=D", -1, -1, false, false, "", NULL, false}, + {";A=B,C=D", -1, -1, false, false, "A=B,C=D", NULL, false}, + {";A=B,C=D", -1, -1, false, true, "A=B,C=D", NULL, false}, + {";A=B,C=D", 2, 1, false, false, "A=B,C=D", ";A=B,C=D", true}, {"x=🔥", 1, 0, false, false, "x=🔥", "x=🔥", true}, + {"@FOO", 0, 0, true, false, "@FOO", "@FOO", true}, + }; + + struct ldb_dn_extended_syntax syntax = { + .name = "ID", + .read_fn = extended_dn_read_ID, + .write_clear_fn = extended_dn_write_ID, + .write_hex_fn = extended_dn_write_ID }; + ldb_dn_extended_add_syntax(ldb, 0, &syntax); for (i = 0; i < ARRAY_SIZE(tests); i++) { bool result; @@ -152,11 +197,11 @@ static void test_ldb_dn_explode(void **state) ext_linear = ldb_dn_get_extended_linearized(ldb, dn, 1); assert_true((ext_linear == NULL) == - (tests[i].ext_linearized == NULL)); + (tests[i].ext_linearized_1 == NULL)); - if (tests[i].ext_linearized != NULL) { + if (tests[i].ext_linearized_1 != NULL) { assert_string_equal(ext_linear, - tests[i].ext_linearized); + tests[i].ext_linearized_1); } assert_true(ldb_dn_is_special(dn) == tests[i].special); assert_true(ldb_dn_is_valid(dn) != tests[i].invalid); -- 2.17.1 From bc0d16c9d8eacd254552ff28726a2ba5f2a1c8c0 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 28 Aug 2019 17:44:52 +1200 Subject: [PATCH 132/376] ldb: Release ldb 2.0.7 * Robustness improvements against duplicate attributes in ldb_filter_attrs() (bug 13695) * Robustness improvements against invalid string DN values (bug 14049) Signed-off-by: Andrew Bartlett Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Wed Sep 4 10:24:56 UTC 2019 on sn-devel-184 --- lib/ldb/ABI/ldb-2.0.7.sigs | 283 ++++++++++++++++++++++++++++++ lib/ldb/ABI/pyldb-util-2.0.7.sigs | 2 + lib/ldb/wscript | 2 +- 3 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 lib/ldb/ABI/ldb-2.0.7.sigs create mode 100644 lib/ldb/ABI/pyldb-util-2.0.7.sigs diff --git a/lib/ldb/ABI/ldb-2.0.7.sigs b/lib/ldb/ABI/ldb-2.0.7.sigs new file mode 100644 index 00000000000..5049dc64ce1 --- /dev/null +++ b/lib/ldb/ABI/ldb-2.0.7.sigs @@ -0,0 +1,283 @@ +ldb_add: int (struct ldb_context *, const struct ldb_message *) +ldb_any_comparison: int (struct ldb_context *, void *, ldb_attr_handler_t, const struct ldb_val *, const struct ldb_val *) +ldb_asprintf_errstring: void (struct ldb_context *, const char *, ...) +ldb_attr_casefold: char *(TALLOC_CTX *, const char *) +ldb_attr_dn: int (const char *) +ldb_attr_in_list: int (const char * const *, const char *) +ldb_attr_list_copy: const char **(TALLOC_CTX *, const char * const *) +ldb_attr_list_copy_add: const char **(TALLOC_CTX *, const char * const *, const char *) +ldb_base64_decode: int (char *) +ldb_base64_encode: char *(TALLOC_CTX *, const char *, int) +ldb_binary_decode: struct ldb_val (TALLOC_CTX *, const char *) +ldb_binary_encode: char *(TALLOC_CTX *, struct ldb_val) +ldb_binary_encode_string: char *(TALLOC_CTX *, const char *) +ldb_build_add_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_del_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_extended_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const char *, void *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_mod_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_rename_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, struct ldb_dn *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_search_req: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, const char *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_build_search_req_ex: int (struct ldb_request **, struct ldb_context *, TALLOC_CTX *, struct ldb_dn *, enum ldb_scope, struct ldb_parse_tree *, const char * const *, struct ldb_control **, void *, ldb_request_callback_t, struct ldb_request *) +ldb_casefold: char *(struct ldb_context *, TALLOC_CTX *, const char *, size_t) +ldb_casefold_default: char *(void *, TALLOC_CTX *, const char *, size_t) +ldb_check_critical_controls: int (struct ldb_control **) +ldb_comparison_binary: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *) +ldb_comparison_fold: int (struct ldb_context *, void *, const struct ldb_val *, const struct ldb_val *) +ldb_connect: int (struct ldb_context *, const char *, unsigned int, const char **) +ldb_control_to_string: char *(TALLOC_CTX *, const struct ldb_control *) +ldb_controls_except_specified: struct ldb_control **(struct ldb_control **, TALLOC_CTX *, struct ldb_control *) +ldb_debug: void (struct ldb_context *, enum ldb_debug_level, const char *, ...) +ldb_debug_add: void (struct ldb_context *, const char *, ...) +ldb_debug_end: void (struct ldb_context *, enum ldb_debug_level) +ldb_debug_set: void (struct ldb_context *, enum ldb_debug_level, const char *, ...) +ldb_delete: int (struct ldb_context *, struct ldb_dn *) +ldb_dn_add_base: bool (struct ldb_dn *, struct ldb_dn *) +ldb_dn_add_base_fmt: bool (struct ldb_dn *, const char *, ...) +ldb_dn_add_child: bool (struct ldb_dn *, struct ldb_dn *) +ldb_dn_add_child_fmt: bool (struct ldb_dn *, const char *, ...) +ldb_dn_add_child_val: bool (struct ldb_dn *, const char *, struct ldb_val) +ldb_dn_alloc_casefold: char *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_alloc_linearized: char *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_canonical_ex_string: char *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_canonical_string: char *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_check_local: bool (struct ldb_module *, struct ldb_dn *) +ldb_dn_check_special: bool (struct ldb_dn *, const char *) +ldb_dn_compare: int (struct ldb_dn *, struct ldb_dn *) +ldb_dn_compare_base: int (struct ldb_dn *, struct ldb_dn *) +ldb_dn_copy: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_escape_value: char *(TALLOC_CTX *, struct ldb_val) +ldb_dn_extended_add_syntax: int (struct ldb_context *, unsigned int, const struct ldb_dn_extended_syntax *) +ldb_dn_extended_filter: void (struct ldb_dn *, const char * const *) +ldb_dn_extended_syntax_by_name: const struct ldb_dn_extended_syntax *(struct ldb_context *, const char *) +ldb_dn_from_ldb_val: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const struct ldb_val *) +ldb_dn_get_casefold: const char *(struct ldb_dn *) +ldb_dn_get_comp_num: int (struct ldb_dn *) +ldb_dn_get_component_name: const char *(struct ldb_dn *, unsigned int) +ldb_dn_get_component_val: const struct ldb_val *(struct ldb_dn *, unsigned int) +ldb_dn_get_extended_comp_num: int (struct ldb_dn *) +ldb_dn_get_extended_component: const struct ldb_val *(struct ldb_dn *, const char *) +ldb_dn_get_extended_linearized: char *(TALLOC_CTX *, struct ldb_dn *, int) +ldb_dn_get_ldb_context: struct ldb_context *(struct ldb_dn *) +ldb_dn_get_linearized: const char *(struct ldb_dn *) +ldb_dn_get_parent: struct ldb_dn *(TALLOC_CTX *, struct ldb_dn *) +ldb_dn_get_rdn_name: const char *(struct ldb_dn *) +ldb_dn_get_rdn_val: const struct ldb_val *(struct ldb_dn *) +ldb_dn_has_extended: bool (struct ldb_dn *) +ldb_dn_is_null: bool (struct ldb_dn *) +ldb_dn_is_special: bool (struct ldb_dn *) +ldb_dn_is_valid: bool (struct ldb_dn *) +ldb_dn_map_local: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) +ldb_dn_map_rebase_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) +ldb_dn_map_remote: struct ldb_dn *(struct ldb_module *, void *, struct ldb_dn *) +ldb_dn_minimise: bool (struct ldb_dn *) +ldb_dn_new: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *) +ldb_dn_new_fmt: struct ldb_dn *(TALLOC_CTX *, struct ldb_context *, const char *, ...) +ldb_dn_remove_base_components: bool (struct ldb_dn *, unsigned int) +ldb_dn_remove_child_components: bool (struct ldb_dn *, unsigned int) +ldb_dn_remove_extended_components: void (struct ldb_dn *) +ldb_dn_replace_components: bool (struct ldb_dn *, struct ldb_dn *) +ldb_dn_set_component: int (struct ldb_dn *, int, const char *, const struct ldb_val) +ldb_dn_set_extended_component: int (struct ldb_dn *, const char *, const struct ldb_val *) +ldb_dn_update_components: int (struct ldb_dn *, const struct ldb_dn *) +ldb_dn_validate: bool (struct ldb_dn *) +ldb_dump_results: void (struct ldb_context *, struct ldb_result *, FILE *) +ldb_error_at: int (struct ldb_context *, int, const char *, const char *, int) +ldb_errstring: const char *(struct ldb_context *) +ldb_extended: int (struct ldb_context *, const char *, void *, struct ldb_result **) +ldb_extended_default_callback: int (struct ldb_request *, struct ldb_reply *) +ldb_filter_attrs: int (struct ldb_context *, const struct ldb_message *, const char * const *, struct ldb_message *) +ldb_filter_from_tree: char *(TALLOC_CTX *, const struct ldb_parse_tree *) +ldb_get_config_basedn: struct ldb_dn *(struct ldb_context *) +ldb_get_create_perms: unsigned int (struct ldb_context *) +ldb_get_default_basedn: struct ldb_dn *(struct ldb_context *) +ldb_get_event_context: struct tevent_context *(struct ldb_context *) +ldb_get_flags: unsigned int (struct ldb_context *) +ldb_get_opaque: void *(struct ldb_context *, const char *) +ldb_get_root_basedn: struct ldb_dn *(struct ldb_context *) +ldb_get_schema_basedn: struct ldb_dn *(struct ldb_context *) +ldb_global_init: int (void) +ldb_handle_get_event_context: struct tevent_context *(struct ldb_handle *) +ldb_handle_new: struct ldb_handle *(TALLOC_CTX *, struct ldb_context *) +ldb_handle_use_global_event_context: void (struct ldb_handle *) +ldb_handler_copy: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *) +ldb_handler_fold: int (struct ldb_context *, void *, const struct ldb_val *, struct ldb_val *) +ldb_init: struct ldb_context *(TALLOC_CTX *, struct tevent_context *) +ldb_ldif_message_redacted_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *) +ldb_ldif_message_string: char *(struct ldb_context *, TALLOC_CTX *, enum ldb_changetype, const struct ldb_message *) +ldb_ldif_parse_modrdn: int (struct ldb_context *, const struct ldb_ldif *, TALLOC_CTX *, struct ldb_dn **, struct ldb_dn **, bool *, struct ldb_dn **, struct ldb_dn **) +ldb_ldif_read: struct ldb_ldif *(struct ldb_context *, int (*)(void *), void *) +ldb_ldif_read_file: struct ldb_ldif *(struct ldb_context *, FILE *) +ldb_ldif_read_file_state: struct ldb_ldif *(struct ldb_context *, struct ldif_read_file_state *) +ldb_ldif_read_free: void (struct ldb_context *, struct ldb_ldif *) +ldb_ldif_read_string: struct ldb_ldif *(struct ldb_context *, const char **) +ldb_ldif_write: int (struct ldb_context *, int (*)(void *, const char *, ...), void *, const struct ldb_ldif *) +ldb_ldif_write_file: int (struct ldb_context *, FILE *, const struct ldb_ldif *) +ldb_ldif_write_redacted_trace_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *) +ldb_ldif_write_string: char *(struct ldb_context *, TALLOC_CTX *, const struct ldb_ldif *) +ldb_load_modules: int (struct ldb_context *, const char **) +ldb_map_add: int (struct ldb_module *, struct ldb_request *) +ldb_map_delete: int (struct ldb_module *, struct ldb_request *) +ldb_map_init: int (struct ldb_module *, const struct ldb_map_attribute *, const struct ldb_map_objectclass *, const char * const *, const char *, const char *) +ldb_map_modify: int (struct ldb_module *, struct ldb_request *) +ldb_map_rename: int (struct ldb_module *, struct ldb_request *) +ldb_map_search: int (struct ldb_module *, struct ldb_request *) +ldb_match_message: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, enum ldb_scope, bool *) +ldb_match_msg: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope) +ldb_match_msg_error: int (struct ldb_context *, const struct ldb_message *, const struct ldb_parse_tree *, struct ldb_dn *, enum ldb_scope, bool *) +ldb_match_msg_objectclass: int (const struct ldb_message *, const char *) +ldb_mod_register_control: int (struct ldb_module *, const char *) +ldb_modify: int (struct ldb_context *, const struct ldb_message *) +ldb_modify_default_callback: int (struct ldb_request *, struct ldb_reply *) +ldb_module_call_chain: char *(struct ldb_request *, TALLOC_CTX *) +ldb_module_connect_backend: int (struct ldb_context *, const char *, const char **, struct ldb_module **) +ldb_module_done: int (struct ldb_request *, struct ldb_control **, struct ldb_extended *, int) +ldb_module_flags: uint32_t (struct ldb_context *) +ldb_module_get_ctx: struct ldb_context *(struct ldb_module *) +ldb_module_get_name: const char *(struct ldb_module *) +ldb_module_get_ops: const struct ldb_module_ops *(struct ldb_module *) +ldb_module_get_private: void *(struct ldb_module *) +ldb_module_init_chain: int (struct ldb_context *, struct ldb_module *) +ldb_module_load_list: int (struct ldb_context *, const char **, struct ldb_module *, struct ldb_module **) +ldb_module_new: struct ldb_module *(TALLOC_CTX *, struct ldb_context *, const char *, const struct ldb_module_ops *) +ldb_module_next: struct ldb_module *(struct ldb_module *) +ldb_module_popt_options: struct poptOption **(struct ldb_context *) +ldb_module_send_entry: int (struct ldb_request *, struct ldb_message *, struct ldb_control **) +ldb_module_send_referral: int (struct ldb_request *, char *) +ldb_module_set_next: void (struct ldb_module *, struct ldb_module *) +ldb_module_set_private: void (struct ldb_module *, void *) +ldb_modules_hook: int (struct ldb_context *, enum ldb_module_hook_type) +ldb_modules_list_from_string: const char **(struct ldb_context *, TALLOC_CTX *, const char *) +ldb_modules_load: int (const char *, const char *) +ldb_msg_add: int (struct ldb_message *, const struct ldb_message_element *, int) +ldb_msg_add_empty: int (struct ldb_message *, const char *, int, struct ldb_message_element **) +ldb_msg_add_fmt: int (struct ldb_message *, const char *, const char *, ...) +ldb_msg_add_linearized_dn: int (struct ldb_message *, const char *, struct ldb_dn *) +ldb_msg_add_steal_string: int (struct ldb_message *, const char *, char *) +ldb_msg_add_steal_value: int (struct ldb_message *, const char *, struct ldb_val *) +ldb_msg_add_string: int (struct ldb_message *, const char *, const char *) +ldb_msg_add_value: int (struct ldb_message *, const char *, const struct ldb_val *, struct ldb_message_element **) +ldb_msg_canonicalize: struct ldb_message *(struct ldb_context *, const struct ldb_message *) +ldb_msg_check_string_attribute: int (const struct ldb_message *, const char *, const char *) +ldb_msg_copy: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *) +ldb_msg_copy_attr: int (struct ldb_message *, const char *, const char *) +ldb_msg_copy_shallow: struct ldb_message *(TALLOC_CTX *, const struct ldb_message *) +ldb_msg_diff: struct ldb_message *(struct ldb_context *, struct ldb_message *, struct ldb_message *) +ldb_msg_difference: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message *, struct ldb_message *, struct ldb_message **) +ldb_msg_element_compare: int (struct ldb_message_element *, struct ldb_message_element *) +ldb_msg_element_compare_name: int (struct ldb_message_element *, struct ldb_message_element *) +ldb_msg_element_equal_ordered: bool (const struct ldb_message_element *, const struct ldb_message_element *) +ldb_msg_find_attr_as_bool: int (const struct ldb_message *, const char *, int) +ldb_msg_find_attr_as_dn: struct ldb_dn *(struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, const char *) +ldb_msg_find_attr_as_double: double (const struct ldb_message *, const char *, double) +ldb_msg_find_attr_as_int: int (const struct ldb_message *, const char *, int) +ldb_msg_find_attr_as_int64: int64_t (const struct ldb_message *, const char *, int64_t) +ldb_msg_find_attr_as_string: const char *(const struct ldb_message *, const char *, const char *) +ldb_msg_find_attr_as_uint: unsigned int (const struct ldb_message *, const char *, unsigned int) +ldb_msg_find_attr_as_uint64: uint64_t (const struct ldb_message *, const char *, uint64_t) +ldb_msg_find_common_values: int (struct ldb_context *, TALLOC_CTX *, struct ldb_message_element *, struct ldb_message_element *, uint32_t) +ldb_msg_find_duplicate_val: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message_element *, struct ldb_val **, uint32_t) +ldb_msg_find_element: struct ldb_message_element *(const struct ldb_message *, const char *) +ldb_msg_find_ldb_val: const struct ldb_val *(const struct ldb_message *, const char *) +ldb_msg_find_val: struct ldb_val *(const struct ldb_message_element *, struct ldb_val *) +ldb_msg_new: struct ldb_message *(TALLOC_CTX *) +ldb_msg_normalize: int (struct ldb_context *, TALLOC_CTX *, const struct ldb_message *, struct ldb_message **) +ldb_msg_remove_attr: void (struct ldb_message *, const char *) +ldb_msg_remove_element: void (struct ldb_message *, struct ldb_message_element *) +ldb_msg_rename_attr: int (struct ldb_message *, const char *, const char *) +ldb_msg_sanity_check: int (struct ldb_context *, const struct ldb_message *) +ldb_msg_sort_elements: void (struct ldb_message *) +ldb_next_del_trans: int (struct ldb_module *) +ldb_next_end_trans: int (struct ldb_module *) +ldb_next_init: int (struct ldb_module *) +ldb_next_prepare_commit: int (struct ldb_module *) +ldb_next_read_lock: int (struct ldb_module *) +ldb_next_read_unlock: int (struct ldb_module *) +ldb_next_remote_request: int (struct ldb_module *, struct ldb_request *) +ldb_next_request: int (struct ldb_module *, struct ldb_request *) +ldb_next_start_trans: int (struct ldb_module *) +ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *) +ldb_options_copy: const char **(TALLOC_CTX *, const char **) +ldb_options_find: const char *(struct ldb_context *, const char **, const char *) +ldb_options_get: const char **(struct ldb_context *) +ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t) +ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *) +ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **) +ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *) +ldb_parse_tree_attr_replace: void (struct ldb_parse_tree *, const char *, const char *) +ldb_parse_tree_copy_shallow: struct ldb_parse_tree *(TALLOC_CTX *, const struct ldb_parse_tree *) +ldb_parse_tree_walk: int (struct ldb_parse_tree *, int (*)(struct ldb_parse_tree *, void *), void *) +ldb_qsort: void (void * const, size_t, size_t, void *, ldb_qsort_cmp_fn_t) +ldb_register_backend: int (const char *, ldb_connect_fn, bool) +ldb_register_extended_match_rule: int (struct ldb_context *, const struct ldb_extended_match_rule *) +ldb_register_hook: int (ldb_hook_fn) +ldb_register_module: int (const struct ldb_module_ops *) +ldb_rename: int (struct ldb_context *, struct ldb_dn *, struct ldb_dn *) +ldb_reply_add_control: int (struct ldb_reply *, const char *, bool, void *) +ldb_reply_get_control: struct ldb_control *(struct ldb_reply *, const char *) +ldb_req_get_custom_flags: uint32_t (struct ldb_request *) +ldb_req_is_untrusted: bool (struct ldb_request *) +ldb_req_location: const char *(struct ldb_request *) +ldb_req_mark_trusted: void (struct ldb_request *) +ldb_req_mark_untrusted: void (struct ldb_request *) +ldb_req_set_custom_flags: void (struct ldb_request *, uint32_t) +ldb_req_set_location: void (struct ldb_request *, const char *) +ldb_request: int (struct ldb_context *, struct ldb_request *) +ldb_request_add_control: int (struct ldb_request *, const char *, bool, void *) +ldb_request_done: int (struct ldb_request *, int) +ldb_request_get_control: struct ldb_control *(struct ldb_request *, const char *) +ldb_request_get_status: int (struct ldb_request *) +ldb_request_replace_control: int (struct ldb_request *, const char *, bool, void *) +ldb_request_set_state: void (struct ldb_request *, int) +ldb_reset_err_string: void (struct ldb_context *) +ldb_save_controls: int (struct ldb_control *, struct ldb_request *, struct ldb_control ***) +ldb_schema_attribute_add: int (struct ldb_context *, const char *, unsigned int, const char *) +ldb_schema_attribute_add_with_syntax: int (struct ldb_context *, const char *, unsigned int, const struct ldb_schema_syntax *) +ldb_schema_attribute_by_name: const struct ldb_schema_attribute *(struct ldb_context *, const char *) +ldb_schema_attribute_fill_with_syntax: int (struct ldb_context *, TALLOC_CTX *, const char *, unsigned int, const struct ldb_schema_syntax *, struct ldb_schema_attribute *) +ldb_schema_attribute_remove: void (struct ldb_context *, const char *) +ldb_schema_attribute_remove_flagged: void (struct ldb_context *, unsigned int) +ldb_schema_attribute_set_override_handler: void (struct ldb_context *, ldb_attribute_handler_override_fn_t, void *) +ldb_schema_set_override_GUID_index: void (struct ldb_context *, const char *, const char *) +ldb_schema_set_override_indexlist: void (struct ldb_context *, bool) +ldb_search: int (struct ldb_context *, TALLOC_CTX *, struct ldb_result **, struct ldb_dn *, enum ldb_scope, const char * const *, const char *, ...) +ldb_search_default_callback: int (struct ldb_request *, struct ldb_reply *) +ldb_sequence_number: int (struct ldb_context *, enum ldb_sequence_type, uint64_t *) +ldb_set_create_perms: void (struct ldb_context *, unsigned int) +ldb_set_debug: int (struct ldb_context *, void (*)(void *, enum ldb_debug_level, const char *, va_list), void *) +ldb_set_debug_stderr: int (struct ldb_context *) +ldb_set_default_dns: void (struct ldb_context *) +ldb_set_errstring: void (struct ldb_context *, const char *) +ldb_set_event_context: void (struct ldb_context *, struct tevent_context *) +ldb_set_flags: void (struct ldb_context *, unsigned int) +ldb_set_modules_dir: void (struct ldb_context *, const char *) +ldb_set_opaque: int (struct ldb_context *, const char *, void *) +ldb_set_require_private_event_context: void (struct ldb_context *) +ldb_set_timeout: int (struct ldb_context *, struct ldb_request *, int) +ldb_set_timeout_from_prev_req: int (struct ldb_context *, struct ldb_request *, struct ldb_request *) +ldb_set_utf8_default: void (struct ldb_context *) +ldb_set_utf8_fns: void (struct ldb_context *, void *, char *(*)(void *, void *, const char *, size_t)) +ldb_setup_wellknown_attributes: int (struct ldb_context *) +ldb_should_b64_encode: int (struct ldb_context *, const struct ldb_val *) +ldb_standard_syntax_by_name: const struct ldb_schema_syntax *(struct ldb_context *, const char *) +ldb_strerror: const char *(int) +ldb_string_to_time: time_t (const char *) +ldb_string_utc_to_time: time_t (const char *) +ldb_timestring: char *(TALLOC_CTX *, time_t) +ldb_timestring_utc: char *(TALLOC_CTX *, time_t) +ldb_transaction_cancel: int (struct ldb_context *) +ldb_transaction_cancel_noerr: int (struct ldb_context *) +ldb_transaction_commit: int (struct ldb_context *) +ldb_transaction_prepare_commit: int (struct ldb_context *) +ldb_transaction_start: int (struct ldb_context *) +ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *) +ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int) +ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *) +ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *) +ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *) +ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *) +ldb_val_map_remote: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *) +ldb_val_string_cmp: int (const struct ldb_val *, const char *) +ldb_val_to_time: int (const struct ldb_val *, time_t *) +ldb_valid_attr_name: int (const char *) +ldb_vdebug: void (struct ldb_context *, enum ldb_debug_level, const char *, va_list) +ldb_wait: int (struct ldb_handle *, enum ldb_wait_type) diff --git a/lib/ldb/ABI/pyldb-util-2.0.7.sigs b/lib/ldb/ABI/pyldb-util-2.0.7.sigs new file mode 100644 index 00000000000..74d6719d2bc --- /dev/null +++ b/lib/ldb/ABI/pyldb-util-2.0.7.sigs @@ -0,0 +1,2 @@ +pyldb_Dn_FromDn: PyObject *(struct ldb_dn *) +pyldb_Object_AsDn: bool (TALLOC_CTX *, PyObject *, struct ldb_context *, struct ldb_dn **) diff --git a/lib/ldb/wscript b/lib/ldb/wscript index f928e2c739c..750306fbddb 100644 --- a/lib/ldb/wscript +++ b/lib/ldb/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'ldb' -VERSION = '2.0.6' +VERSION = '2.0.7' import sys, os -- 2.17.1 From 116f8cfe3041676264f2bfa2ca43d6266cb326ab Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 5 Sep 2019 11:23:22 +1200 Subject: [PATCH 133/376] docs: Deprecate "lanman auth = yes" This feature is only available for SMB1 and we need to warn users that this is going away soon, and allow the removal in a future release under our rules for parameter deprecation. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14117 Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Thu Sep 5 04:04:18 UTC 2019 on sn-devel-184 (cherry picked from commit 1006f7abe8980d2c01c181db93225353ce494b3a) --- docs-xml/smbdotconf/security/lanmanauth.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs-xml/smbdotconf/security/lanmanauth.xml b/docs-xml/smbdotconf/security/lanmanauth.xml index 97f2fb04dcb..e5e63e43076 100644 --- a/docs-xml/smbdotconf/security/lanmanauth.xml +++ b/docs-xml/smbdotconf/security/lanmanauth.xml @@ -2,8 +2,17 @@ context="G" type="boolean" function="_lanman_auth" + deprecated="1" xmlns:samba="http://www.samba.org/samba/DTD/samba-doc"> + This parameter has been deprecated since Samba 4.11 and + support for LanMan (as distinct from NTLM, NTLMv2 or + Kerberos authentication) + will be removed in a future Samba release. + That is, in the future, the current default of + lanman auth = no + will be the enforced behaviour. + This parameter determines whether or not smbd 8 will attempt to authenticate users or permit password changes -- 2.17.1 From f1d2b5eba72df50f98860557e3d3523b1e82f625 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 5 Sep 2019 11:19:10 +1200 Subject: [PATCH 134/376] docs: Deprecate "encrypt passwords = no" This feature is only available for SMB1 and we need to warn users that this is going away soon, and allow the removal in a future release under our rules for parameter deprecation. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14117 Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam (cherry picked from commit 8d0d99a4d78ba408bb45e2d693049025e60e277a) --- docs-xml/smbdotconf/security/encryptpasswords.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs-xml/smbdotconf/security/encryptpasswords.xml b/docs-xml/smbdotconf/security/encryptpasswords.xml index 4bd97809d86..4fdfa898501 100644 --- a/docs-xml/smbdotconf/security/encryptpasswords.xml +++ b/docs-xml/smbdotconf/security/encryptpasswords.xml @@ -1,8 +1,16 @@ + This parameter has been deprecated since Samba 4.11 and + support for plaintext (as distinct from NTLM, NTLMv2 + or Kerberos authentication) + will be removed in a future Samba release. + That is, in the future, the current default of + encrypt passwords = yes + will be the enforced behaviour. This boolean controls whether encrypted passwords will be negotiated with the client. Note that Windows NT 4.0 SP3 and above and also Windows 98 will by default expect encrypted passwords -- 2.17.1 From 04867f4c513c70313f71c59ed3131307c0d1c4dc Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 5 Sep 2019 16:12:10 +1200 Subject: [PATCH 135/376] WHATSNEW: Add entry for deprecation of "lanman auth" and "encrypt passwords = no" BUG: https://bugzilla.samba.org/show_bug.cgi?id=14117 Signed-off-by: Andrew Bartlett --- WHATSNEW.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index eece43fcd9e..904db5fefc3 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -68,6 +68,18 @@ in the following years. If you have a strong requirement for SMB1 (except for supporting old Linux Kernels), please file a bug at https://bugzilla.samba.org and let us know about the details. +LanMan and plaintext authentication deprecated +---------------------------------------------- + +The "lanman auth" and "encrypt passwords" parameters are deprecated +with this release as both are only applicable to SMB1 and are quite +insecure. NTLM, NTLMv2 and Kerberos authentication are unaffected, as +"encrypt passwords = yes" has been the default since Samba 3.0.0. + +If you have a strong requirement for these authentication protocols, +please file a bug at https://bugzilla.samba.org and let us know about +the details. + BIND9_FLATFILE deprecated ------------------------- @@ -357,6 +369,8 @@ smb.conf changes fruit:zero_file_id Changed default False debug encryption New: dump encryption keys False rndc command Deprecated + lanman auth Deprecated + encrypt passwords Deprecated CHANGES SINCE 4.11.0rc2 -- 2.17.1 From 11c2b21b97d2d8fcd46c7e3ac8005e940869bc51 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 12 Jul 2019 10:49:13 +0200 Subject: [PATCH 136/376] ctdb: fix compilation on systems with glibc robust mutexes On older systems like SLES 11 without POSIX robust mutexes, but with glib robust mutexes where all the functions are available but have a "_np" suffix, compilation fails in: ctdb/tests/src/test_mutex_raw.c.239.o: In function `worker': /root/samba-4.10.6/bin/default/../../ctdb/tests/src/test_mutex_raw.c:129: undefined reference to `pthread_mutex_consistent' ctdb/tests/src/test_mutex_raw.c.239.o: In function `main': /root/samba-4.10.6/bin/default/../../ctdb/tests/src/test_mutex_raw.c:285: undefined reference to `pthread_mutex_consistent' /root/samba-4.10.6/bin/default/../../ctdb/tests/src/test_mutex_raw.c:332: undefined reference to `pthread_mutexattr_setrobust' /root/samba-4.10.6/bin/default/../../ctdb/tests/src/test_mutex_raw.c:363: undefined reference to `pthread_mutex_consistent' collect2: ld returned 1 exit status This could be fixed by using libreplace system/threads.h instead of pthreads.h directly, but as there has been a desire to keep test_mutex_raw.c standalone and compilable without other external depenencies then libc and libpthread, make the tool developer build only. This should get the average user over the cliff. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14038 RN: Fix compiling ctdb on older systems lacking POSIX robust mutexes Signed-off-by: Ralph Boehme Reviewed-by: Martin Schwenke (cherry picked from commit f5388f97792ac2d7962950dad91aaf8ad49bceaa) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Fri Sep 6 08:19:44 UTC 2019 on sn-devel-184 --- ctdb/wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/wscript b/ctdb/wscript index 51a09fdc63d..9663213a2a8 100644 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -1040,7 +1040,7 @@ def build(bld): ib_deps, install_path='${CTDB_TEST_LIBEXECDIR}') - if bld.env.HAVE_ROBUST_MUTEXES and sys.platform.startswith('linux'): + if bld.env.HAVE_ROBUST_MUTEXES and sys.platform.startswith('linux') and bld.env.DEVELOPER: bld.SAMBA_BINARY('test_mutex_raw', source='tests/src/test_mutex_raw.c', deps='pthread', -- 2.17.1 From bff4ee33420557c6b80646a94de926d4f4c0f24d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 25 Jul 2019 14:37:31 +0200 Subject: [PATCH 137/376] libcli/smb: add new COMPRESSION and NETNAME negotiate context ids BUG: https://bugzilla.samba.org/show_bug.cgi?id=14055 Signed-off-by: Stefan Metzmacher Reviewed-by: Aurelien Aptel (cherry picked from commit e10b90f33bb812600886656a1124e2d434416563) --- libcli/smb/smb2_constants.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcli/smb/smb2_constants.h b/libcli/smb/smb2_constants.h index 3dd462cdd69..1430f02689c 100644 --- a/libcli/smb/smb2_constants.h +++ b/libcli/smb/smb2_constants.h @@ -131,6 +131,8 @@ /* Types of SMB2 Negotiate Contexts - only in dialect >= 0x310 */ #define SMB2_PREAUTH_INTEGRITY_CAPABILITIES 0x0001 #define SMB2_ENCRYPTION_CAPABILITIES 0x0002 +#define SMB2_COMPRESSION_CAPABILITIES 0x0003 +#define SMB2_NETNAME_NEGOTIATE_CONTEXT_ID 0x0005 /* Values for the SMB2_PREAUTH_INTEGRITY_CAPABILITIES Context (>= 0x310) */ #define SMB2_PREAUTH_INTEGRITY_SHA512 0x0001 -- 2.17.1 From d01dbe68cdfcd873f53c02c9529a944bf209c58f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 25 Jul 2019 14:38:26 +0200 Subject: [PATCH 138/376] libcli/smb: send SMB2_NETNAME_NEGOTIATE_CONTEXT_ID Note: Unlike the current documentation, the utf16 string is not null-terminated, that matches Windows Server 1903 as a client. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14055 RN: Add the target server name of SMB 3.1.1 connections as a hint to load balancers or servers with "multi-tenancy" support. Signed-off-by: Stefan Metzmacher Reviewed-by: Aurelien Aptel (cherry picked from commit 21f6cece543dd791e0f4636458bfe9819823420c) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Mon Sep 9 12:03:55 UTC 2019 on sn-devel-184 --- libcli/smb/smbXcli_base.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 2f5fac08128..c9b396106ae 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -4770,6 +4770,8 @@ static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_sta if (state->conn->max_protocol >= PROTOCOL_SMB3_10) { NTSTATUS status; struct smb2_negotiate_contexts c = { .num_contexts = 0, }; + uint8_t *netname_utf16 = NULL; + size_t netname_utf16_len = 0; uint32_t offset; DATA_BLOB b; uint8_t p[38]; @@ -4802,6 +4804,21 @@ static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_sta return NULL; } + ok = convert_string_talloc(state, CH_UNIX, CH_UTF16, + state->conn->remote_name, + strlen(state->conn->remote_name), + &netname_utf16, &netname_utf16_len); + if (!ok) { + return NULL; + } + + status = smb2_negotiate_context_add(state, &c, + SMB2_NETNAME_NEGOTIATE_CONTEXT_ID, + netname_utf16, netname_utf16_len); + if (!NT_STATUS_IS_OK(status)) { + return NULL; + } + status = smb2_negotiate_context_push(state, &b, c); if (!NT_STATUS_IS_OK(status)) { return NULL; -- 2.17.1 From 728e29d84ca594a5607f072e50de60deaa9da45e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 4 Sep 2019 12:50:06 +0200 Subject: [PATCH 139/376] s3:blocking: call change_to_user_by_fsp() when dbwrap_watched_watch* finishes This is not strictly required as fd-based calls are used, but it's more consistent to call SMB_VFS_BRL_LOCK_WINDOWS() in the same environment on retry. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 28ac2cbaf92a8619f0380f024c5a220d9fdc4622) --- source3/smbd/blocking.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index ffc3142b74c..ca8a625ba9d 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -334,6 +334,15 @@ static void smbd_smb1_do_locks_retry(struct tevent_req *subreq) NTSTATUS status; bool ok; + /* + * Make sure we run as the user again + */ + ok = change_to_user_by_fsp(state->fsp); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } + status = dbwrap_watched_watch_recv(subreq, NULL, NULL); TALLOC_FREE(subreq); -- 2.17.1 From 80a04a4e19adfe87c5217d75b11e41763f644749 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 4 Sep 2019 12:47:07 +0200 Subject: [PATCH 140/376] s3:smb2_lock: call change_to_user_by_fsp() when dbwrap_watched_watch* finishes This is not strictly required as fd-based calls are used, but it's more consistent to call SMB_VFS_BRL_LOCK_WINDOWS() in the same environment on retry. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 8b565de1acb0fda121cb0bd4cff42d66ee027529) --- source3/smbd/smb2_lock.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 36ec36301b1..e9c8d7f890e 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -421,6 +421,16 @@ static void smbd_smb2_lock_retry(struct tevent_req *subreq) struct server_id blocking_pid = { 0 }; uint64_t blocking_smblctx; NTSTATUS status; + bool ok; + + /* + * Make sure we run as the user again + */ + ok = change_to_user_by_fsp(state->fsp); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } status = dbwrap_watched_watch_recv(subreq, NULL, NULL); TALLOC_FREE(subreq); -- 2.17.1 From 244ad1210cc29ede25fb8692bae46aab7d6725ac Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 5 Sep 2019 08:43:32 +0200 Subject: [PATCH 141/376] s3:locking: add/split out byte_range_{valid,overlap}() helper functions They implement the logic from [MS-FSA]. The following commits will use these functions in other locations. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 0e5613e39d6c6bb892fed939c63b4f14b878803b) --- source3/locking/brlock.c | 109 +++++++++++++++++++++++++++++++++------ source3/locking/proto.h | 6 +++ 2 files changed, 99 insertions(+), 16 deletions(-) diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index cdfd09ceff1..628c2574357 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -96,6 +96,92 @@ static bool brl_same_context(const struct lock_context *ctx1, (ctx1->tid == ctx2->tid)); } +bool byte_range_valid(uint64_t ofs, uint64_t len) +{ + uint64_t max_len = UINT64_MAX - ofs; + uint64_t effective_len; + + /* + * [MS-FSA] specifies this: + * + * If (((FileOffset + Length - 1) < FileOffset) && Length != 0) { + * return STATUS_INVALID_LOCK_RANGE + * } + * + * We avoid integer wrapping and calculate + * max and effective len instead. + */ + + if (len == 0) { + return true; + } + + effective_len = len - 1; + if (effective_len <= max_len) { + return true; + } + + return false; +} + +bool byte_range_overlap(uint64_t ofs1, + uint64_t len1, + uint64_t ofs2, + uint64_t len2) +{ + uint64_t last1; + uint64_t last2; + bool valid; + + /* + * This is based on [MS-FSA] 2.1.4.10 + * Algorithm for Determining If a Range Access + * Conflicts with Byte-Range Locks + */ + + /* + * The {0, 0} range doesn't conflict with any byte-range lock + */ + if (ofs1 == 0 && len1 == 0) { + return false; + } + if (ofs2 == 0 && len2 == 0) { + return false; + } + + /* + * The caller should have checked that the ranges are + * valid. But currently we gracefully handle + * the overflow of a read/write check. + */ + valid = byte_range_valid(ofs1, len1); + if (valid) { + last1 = ofs1 + len1 - 1; + } else { + last1 = UINT64_MAX; + } + valid = byte_range_valid(ofs2, len2); + if (valid) { + last2 = ofs2 + len2 - 1; + } else { + last2 = UINT64_MAX; + } + + /* + * If one range starts after the last + * byte of the other range there's + * no conflict. + */ + if (ofs1 > last2) { + return false; + } + if (ofs2 > last1) { + return false; + } + + return true; +} + /**************************************************************************** See if lck1 and lck2 overlap. ****************************************************************************/ @@ -103,20 +189,10 @@ static bool brl_same_context(const struct lock_context *ctx1, static bool brl_overlap(const struct lock_struct *lck1, const struct lock_struct *lck2) { - /* XXX Remove for Win7 compatibility. */ - /* this extra check is not redundant - it copes with locks - that go beyond the end of 64 bit file space */ - if (lck1->size != 0 && - lck1->start == lck2->start && - lck1->size == lck2->size) { - return True; - } - - if (lck1->start >= (lck2->start+lck2->size) || - lck2->start >= (lck1->start+lck1->size)) { - return False; - } - return True; + return byte_range_overlap(lck1->start, + lck1->size, + lck2->start, + lck2->size); } /**************************************************************************** @@ -336,11 +412,12 @@ NTSTATUS brl_lock_windows_default(struct byte_range_lock *br_lck, files_struct *fsp = br_lck->fsp; struct lock_struct *locks = br_lck->lock_data; NTSTATUS status; + bool valid; SMB_ASSERT(plock->lock_type != UNLOCK_LOCK); - if ((plock->start + plock->size - 1 < plock->start) && - plock->size != 0) { + valid = byte_range_valid(plock->start, plock->size); + if (!valid) { return NT_STATUS_INVALID_LOCK_RANGE; } diff --git a/source3/locking/proto.h b/source3/locking/proto.h index 3a086fa0516..2487fa5d14d 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -31,6 +31,12 @@ void brl_shutdown(void); unsigned int brl_num_locks(const struct byte_range_lock *brl); struct files_struct *brl_fsp(struct byte_range_lock *brl); +bool byte_range_valid(uint64_t ofs, uint64_t len); +bool byte_range_overlap(uint64_t ofs1, + uint64_t len1, + uint64_t ofs2, + uint64_t len2); + NTSTATUS brl_lock_windows_default(struct byte_range_lock *br_lck, struct lock_struct *plock); -- 2.17.1 From f73b670b4db103069aa151d3af4ed7a92ce581c3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 9 Aug 2019 00:47:39 +0200 Subject: [PATCH 142/376] s3:locking: add share_mode_wakeup_waiters() helper function BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit bd8884e5722cbbb7783fb4ae53e4f35b31031b01) --- source3/locking/proto.h | 1 + source3/locking/share_mode_lock.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/source3/locking/proto.h b/source3/locking/proto.h index 2487fa5d14d..7cb8bf3e3c9 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -138,6 +138,7 @@ NTSTATUS share_mode_do_locked( bool *modified_dependent, void *private_data), void *private_data); +NTSTATUS share_mode_wakeup_waiters(struct file_id id); struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, struct file_id id); diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c index 430d14fab4a..372e188c1c0 100644 --- a/source3/locking/share_mode_lock.c +++ b/source3/locking/share_mode_lock.c @@ -771,6 +771,18 @@ NTSTATUS share_mode_do_locked( return NT_STATUS_OK; } +static void share_mode_wakeup_waiters_fn(struct db_record *rec, + bool *modified_dependent, + void *private_data) +{ + *modified_dependent = true; +} + +NTSTATUS share_mode_wakeup_waiters(struct file_id id) +{ + return share_mode_do_locked(id, share_mode_wakeup_waiters_fn, NULL); +} + struct fetch_share_mode_unlocked_state { TALLOC_CTX *mem_ctx; struct share_mode_lock *lck; -- 2.17.1 From 75e07d485944fdc76a6510bf5d450959475e7e5b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2019 19:19:07 +0200 Subject: [PATCH 143/376] s3:blocking: remove unused timeval_brl_min() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 3b788d97f9995e24e4005567f90a925957fb1e00) --- source3/smbd/blocking.c | 16 ---------------- source3/smbd/proto.h | 2 -- 2 files changed, 18 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index ca8a625ba9d..cdc4613270e 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -28,22 +28,6 @@ #undef DBGC_CLASS #define DBGC_CLASS DBGC_LOCKING -/**************************************************************************** - We need a version of timeval_min that treats zero timval as infinite. -****************************************************************************/ - -struct timeval timeval_brl_min(const struct timeval *tv1, - const struct timeval *tv2) -{ - if (timeval_is_zero(tv1)) { - return *tv2; - } - if (timeval_is_zero(tv2)) { - return *tv1; - } - return timeval_min(tv1, tv2); -} - NTSTATUS smbd_do_locks_try( struct files_struct *fsp, enum brl_flavour lock_flav, diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 37eeb9f31ca..b59f1f4123d 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -95,8 +95,6 @@ bool aio_add_req_to_fsp(files_struct *fsp, struct tevent_req *req); /* The following definitions come from smbd/blocking.c */ -struct timeval timeval_brl_min(const struct timeval *tv1, - const struct timeval *tv2); NTSTATUS smbd_do_locks_try( struct files_struct *fsp, enum brl_flavour lock_flav, -- 2.17.1 From 0742879bd8d03333b8b7c2a790afebdb5f7dd92b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 16:10:58 +0200 Subject: [PATCH 144/376] s3:torture: fix the timeout alarm handling on LOCK9 smbXcli_conn_disconnect(alarm_cli->conn, NT_STATUS_OK) means existing requests are not finished with an error, but instead just keep dangling arround. Pass NT_STATUS_LOCAL_DISCONNECT in order to fail the cli_lock32() call after getting SIGALARM. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit e18c8ced8e7a872deb118191595425ef6b826bfa) --- source3/torture/torture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index f26c634b7a7..5a75796928a 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -2543,7 +2543,7 @@ static void alarm_handler(int dummy) static void alarm_handler_parent(int dummy) { - smbXcli_conn_disconnect(alarm_cli->conn, NT_STATUS_OK); + smbXcli_conn_disconnect(alarm_cli->conn, NT_STATUS_LOCAL_DISCONNECT); } static void do_local_lock(int read_fd, int write_fd) -- 2.17.1 From ffdb166e49fa1a786ac1ea4e1ab09c286e75af69 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 14:31:54 +0200 Subject: [PATCH 145/376] s3:torture: convert LOCK9 into LOCK9A and LOCK9B LOCK9A is the original test (with a timeout of -1) and LOCK9B is the same but with timeout of 10 seconds. LOCK9B is needed to demonstrate a server bug in the next commits. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit ac28eec3e4af710feab3be3d4b25bfbe38294431) --- selftest/skip | 2 +- source3/selftest/tests.py | 3 ++- source3/torture/torture.c | 38 ++++++++++++++++++++++++++------------ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/selftest/skip b/selftest/skip index 1e7448acb9f..c471072e88f 100644 --- a/selftest/skip +++ b/selftest/skip @@ -34,7 +34,7 @@ ^samba3.smbtorture_s3.*.pipe_number ^samba3.smbtorture_s3.LOCAL-DBTRANS #hangs for some reason ^samba3.smbtorture_s3.*.DIR1 #loops on 64 bit linux with ext4 -^samba3.smbtorture_s3.plain.LOCK9\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server +^samba3.smbtorture_s3.plain.LOCK9.*\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.OPLOCK2\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.STREAMERROR\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain.DIR1\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 9569aa9ae00..a3daeacae6b 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -78,7 +78,8 @@ plantestsuite("samba3.local_s3", "nt4_dc:local", [os.path.join(samba3srcdir, "sc plantestsuite("samba3.blackbox.registry.upgrade", "nt4_dc:local", [os.path.join(samba3srcdir, "script/tests/test_registry_upgrade.sh"), net, dbwrap_tool]) -tests = ["FDPASS", "LOCK1", "LOCK2", "LOCK3", "LOCK4", "LOCK5", "LOCK6", "LOCK7", "LOCK9", +tests = ["FDPASS", "LOCK1", "LOCK2", "LOCK3", "LOCK4", "LOCK5", "LOCK6", "LOCK7", + "LOCK9A", "LOCK9B", "LOCK10", "LOCK11", "LOCK12", diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 5a75796928a..66dc0cf4d1c 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -2546,7 +2546,7 @@ static void alarm_handler_parent(int dummy) smbXcli_conn_disconnect(alarm_cli->conn, NT_STATUS_LOCAL_DISCONNECT); } -static void do_local_lock(int read_fd, int write_fd) +static void do_local_lock(const char *fname, int read_fd, int write_fd) { int fd; char c = '\0'; @@ -2555,7 +2555,7 @@ static void do_local_lock(int read_fd, int write_fd) int ret; local_pathname = talloc_asprintf(talloc_tos(), - "%s/lockt9.lck", local_path); + "%s/%s", local_path, fname); if (!local_pathname) { printf("child: alloc fail\n"); exit(1); @@ -2614,10 +2614,10 @@ static void do_local_lock(int read_fd, int write_fd) exit(0); } -static bool run_locktest9(int dummy) +static bool _run_locktest9X(const char *fname, int timeout) { struct cli_state *cli1; - const char *fname = "\\lockt9.lck"; + char *fpath = talloc_asprintf(talloc_tos(), "\\%s", fname); uint16_t fnum; bool correct = False; int pipe_in[2], pipe_out[2]; @@ -2628,10 +2628,10 @@ static bool run_locktest9(int dummy) double seconds; NTSTATUS status; - printf("starting locktest9\n"); + printf("starting locktest9X: %s\n", fname); if (local_path == NULL) { - d_fprintf(stderr, "locktest9 must be given a local path via -l \n"); + d_fprintf(stderr, "locktest9X must be given a local path via -l \n"); return false; } @@ -2646,7 +2646,7 @@ static bool run_locktest9(int dummy) if (child_pid == 0) { /* Child. */ - do_local_lock(pipe_out[0], pipe_in[1]); + do_local_lock(fname, pipe_out[0], pipe_in[1]); exit(0); } @@ -2669,7 +2669,7 @@ static bool run_locktest9(int dummy) smbXcli_conn_set_sockopt(cli1->conn, sockops); - status = cli_openx(cli1, fname, O_RDWR, DENY_NONE, + status = cli_openx(cli1, fpath, O_RDWR, DENY_NONE, &fnum); if (!NT_STATUS_IS_OK(status)) { d_fprintf(stderr, "cli_openx returned %s\n", nt_errstr(status)); @@ -2700,7 +2700,7 @@ static bool run_locktest9(int dummy) start = timeval_current(); - status = cli_lock32(cli1, fnum, 0, 4, -1, WRITE_LOCK); + status = cli_lock32(cli1, fnum, 0, 4, timeout, WRITE_LOCK); if (!NT_STATUS_IS_OK(status)) { d_fprintf(stderr, "Unable to apply write lock on range 0:4, error was " "%s\n", nt_errstr(status)); @@ -2727,10 +2727,20 @@ fail: fail_nofd: - printf("finished locktest9\n"); + printf("finished locktest9X: %s\n", fname); return correct; } +static bool run_locktest9a(int dummy) +{ + return _run_locktest9X("lock9a.dat", -1); +} + +static bool run_locktest9b(int dummy) +{ + return _run_locktest9X("lock9b.dat", 10000); +} + struct locktest10_state { bool ok; bool done; @@ -13651,8 +13661,12 @@ static struct { .fn = run_locktest8, }, { - .name = "LOCK9", - .fn = run_locktest9, + .name = "LOCK9A", + .fn = run_locktest9a, + }, + { + .name = "LOCK9B", + .fn = run_locktest9b, }, { .name = "LOCK10", -- 2.17.1 From 841fceae68098160627066dd6bd180948c048d96 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 11:09:47 +0200 Subject: [PATCH 146/376] s3:blocking: demonstrate the posix lock retry fails This is just a temporary commit that shows the bug and its fix. It will be reverted once the problem is fixed. The posix lock retry fails if the client specified timeout is smaller than the hardcoded 1 second retry. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 2ec9e93a7aac2706b4a5931495d56a7b64f8d894) --- selftest/knownfail.d/lock9 | 1 + source3/smbd/blocking.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 selftest/knownfail.d/lock9 diff --git a/selftest/knownfail.d/lock9 b/selftest/knownfail.d/lock9 new file mode 100644 index 00000000000..044622586eb --- /dev/null +++ b/selftest/knownfail.d/lock9 @@ -0,0 +1 @@ +^samba3.smbtorture_s3.*.LOCK9B diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index cdc4613270e..91438fe4486 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -236,7 +236,7 @@ struct tevent_req *smbd_smb1_do_locks_send( DBG_DEBUG("Blocked on a posix lock. Retry in one second\n"); - tmp = timeval_current_ofs(1, 0); + tmp = timeval_current_ofs(15, 0); endtime = timeval_min(&endtime, &tmp); } @@ -381,7 +381,7 @@ static void smbd_smb1_do_locks_retry(struct tevent_req *subreq) DBG_DEBUG("Blocked on a posix lock. Retry in one second\n"); - tmp = timeval_current_ofs(1, 0); + tmp = timeval_current_ofs(15, 0); endtime = timeval_min(&endtime, &tmp); } -- 2.17.1 From b381f4b314c71c446a847de7cdb5baa658455c90 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2019 18:34:36 +0200 Subject: [PATCH 147/376] s3:blocking: split smbd_smb1_do_locks_retry() into _try() and _retry() This will make it possible to have just one caller to smbd_do_locks_try() later and use smbd_smb1_do_locks_try() from within smbd_smb1_do_locks_send(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Reviewed-by: Volker Lendecke Signed-off-by: Stefan Metzmacher (cherry picked from commit e79fcfaaf2ecfca6c3747f6fe4be51f332ebf10d) --- source3/smbd/blocking.c | 72 ++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 91438fe4486..0fa39ae58ab 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -109,6 +109,7 @@ struct smbd_smb1_do_locks_state { uint16_t blocker; }; +static void smbd_smb1_do_locks_try(struct tevent_req *req); static void smbd_smb1_do_locks_retry(struct tevent_req *subreq); static void smbd_smb1_blocked_locks_cleanup( struct tevent_req *req, enum tevent_req_state req_state); @@ -300,10 +301,8 @@ static void smbd_smb1_blocked_locks_cleanup( fsp, blocked, struct tevent_req *, num_blocked-1); } -static void smbd_smb1_do_locks_retry(struct tevent_req *subreq) +static void smbd_smb1_do_locks_try(struct tevent_req *req) { - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); struct smbd_smb1_do_locks_state *state = tevent_req_data( req, struct smbd_smb1_do_locks_state); struct files_struct *fsp = state->fsp; @@ -315,36 +314,10 @@ static void smbd_smb1_do_locks_retry(struct tevent_req *subreq) struct timeval endtime; struct server_id blocking_pid = { 0 }; uint64_t blocking_smblctx = 0; + struct tevent_req *subreq = NULL; NTSTATUS status; bool ok; - /* - * Make sure we run as the user again - */ - ok = change_to_user_by_fsp(state->fsp); - if (!ok) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - - status = dbwrap_watched_watch_recv(subreq, NULL, NULL); - TALLOC_FREE(subreq); - - DBG_DEBUG("dbwrap_watched_watch_recv returned %s\n", - nt_errstr(status)); - - if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { - double elapsed = timeval_elapsed(&state->endtime); - if (elapsed > 0) { - smbd_smb1_brl_finish_by_req( - req, NT_STATUS_FILE_LOCK_CONFLICT); - return; - } - /* - * This is a posix lock retry. Just retry. - */ - } - lck = get_existing_share_mode_lock(state, fsp->file_id); if (tevent_req_nomem(lck, req)) { DBG_DEBUG("Could not get share mode lock\n"); @@ -396,6 +369,45 @@ done: smbd_smb1_brl_finish_by_req(req, status); } +static void smbd_smb1_do_locks_retry(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct smbd_smb1_do_locks_state *state = tevent_req_data( + req, struct smbd_smb1_do_locks_state); + NTSTATUS status; + bool ok; + + /* + * Make sure we run as the user again + */ + ok = change_to_user_by_fsp(state->fsp); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } + + status = dbwrap_watched_watch_recv(subreq, NULL, NULL); + TALLOC_FREE(subreq); + + DBG_DEBUG("dbwrap_watched_watch_recv returned %s\n", + nt_errstr(status)); + + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + double elapsed = timeval_elapsed(&state->endtime); + if (elapsed > 0) { + smbd_smb1_brl_finish_by_req( + req, NT_STATUS_FILE_LOCK_CONFLICT); + return; + } + /* + * This is a posix lock retry. Just retry. + */ + } + + smbd_smb1_do_locks_try(req); +} + NTSTATUS smbd_smb1_do_locks_recv(struct tevent_req *req) { struct smbd_smb1_do_locks_state *state = tevent_req_data( -- 2.17.1 From 6b23f24ee383763c45af8c627df09060d76d9dd8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2019 18:34:36 +0200 Subject: [PATCH 148/376] s3:blocking: move from 'timeout' to 'smbd_smb1_do_locks_state->timeout' This will make it possible to just use smbd_smb1_do_locks_try() in a later commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 8fe708acb43ea36d0cbf398713b125daba180a2d) --- source3/smbd/blocking.c | 20 +++++++++++--------- source3/smbd/proto.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 0fa39ae58ab..81facc43154 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -101,6 +101,7 @@ struct smbd_smb1_do_locks_state { struct tevent_context *ev; struct smb_request *smbreq; struct files_struct *fsp; + uint32_t timeout; struct timeval endtime; bool large_offset; /* required for correct cancel */ enum brl_flavour lock_flav; @@ -119,7 +120,7 @@ struct tevent_req *smbd_smb1_do_locks_send( struct tevent_context *ev, struct smb_request **smbreq, /* talloc_move()d into our state */ struct files_struct *fsp, - uint32_t timeout, + uint32_t lock_timeout, bool large_offset, enum brl_flavour lock_flav, uint16_t num_locks, @@ -142,6 +143,7 @@ struct tevent_req *smbd_smb1_do_locks_send( state->ev = ev; state->smbreq = talloc_move(state, smbreq); state->fsp = fsp; + state->timeout = lock_timeout; state->large_offset = large_offset; state->lock_flav = lock_flav; state->num_locks = num_locks; @@ -155,13 +157,13 @@ struct tevent_req *smbd_smb1_do_locks_send( return tevent_req_post(req, ev); } - if ((timeout != 0) && (timeout != UINT32_MAX)) { + if ((state->timeout != 0) && (state->timeout != UINT32_MAX)) { /* * Windows internal resolution for blocking locks * seems to be about 200ms... Don't wait for less than * that. JRA. */ - timeout = MAX(timeout, lp_lock_spin_time()); + state->timeout = MAX(state->timeout, lp_lock_spin_time()); } lck = get_existing_share_mode_lock(state, state->fsp->file_id); @@ -187,7 +189,7 @@ struct tevent_req *smbd_smb1_do_locks_send( goto done; } - if (timeout == 0) { + if (state->timeout == 0) { struct smbd_lock_element *blocker = &locks[state->blocker]; if ((blocker->offset >= 0xEF000000) && @@ -196,7 +198,7 @@ struct tevent_req *smbd_smb1_do_locks_send( * This must be an optimization of an ancient * application bug... */ - timeout = lp_lock_spin_time(); + state->timeout = lp_lock_spin_time(); } if ((fsp->lock_failure_seen) && @@ -208,15 +210,15 @@ struct tevent_req *smbd_smb1_do_locks_send( */ DBG_DEBUG("Delaying lock request due to previous " "failure\n"); - timeout = lp_lock_spin_time(); + state->timeout = lp_lock_spin_time(); } } DBG_DEBUG("timeout=%"PRIu32", blocking_smblctx=%"PRIu64"\n", - timeout, + state->timeout, blocking_smblctx); - if (timeout == 0) { + if (state->timeout == 0) { tevent_req_nterror(req, status); goto done; } @@ -229,7 +231,7 @@ struct tevent_req *smbd_smb1_do_locks_send( TALLOC_FREE(lck); tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req); - state->endtime = timeval_current_ofs_msec(timeout); + state->endtime = timeval_current_ofs_msec(state->timeout); endtime = state->endtime; if (blocking_smblctx == UINT64_MAX) { diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index b59f1f4123d..cd1ec9a1f9e 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -108,7 +108,7 @@ struct tevent_req *smbd_smb1_do_locks_send( struct tevent_context *ev, struct smb_request **smbreq, /* talloc_move()d into our state */ struct files_struct *fsp, - uint32_t timeout, + uint32_t lock_timeout, bool large_offset, enum brl_flavour lock_flav, uint16_t num_locks, -- 2.17.1 From 2c31c9d365d3aaa323e10abff15fc4404a4a52dd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 14:21:38 +0200 Subject: [PATCH 149/376] s3:blocking: fix posix lock retry We should evaluate the timeout condition after the very last retry and not before. Otherwise we'd fail to retry when waiting for posix locks. The problem happens if the client provided timeout is smaller than the 1 sec (for testing temporary 15 secs) retry. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit e8d719d31f885d7b6d5b317165f90ec40df169c9) --- selftest/knownfail.d/lock9 | 1 - source3/smbd/blocking.c | 36 +++++++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 12 deletions(-) delete mode 100644 selftest/knownfail.d/lock9 diff --git a/selftest/knownfail.d/lock9 b/selftest/knownfail.d/lock9 deleted file mode 100644 index 044622586eb..00000000000 --- a/selftest/knownfail.d/lock9 +++ /dev/null @@ -1 +0,0 @@ -^samba3.smbtorture_s3.*.LOCK9B diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 81facc43154..587923aa5ec 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -319,6 +319,7 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) struct tevent_req *subreq = NULL; NTSTATUS status; bool ok; + double elapsed; lck = get_existing_share_mode_lock(state, fsp->file_id); if (tevent_req_nomem(lck, req)) { @@ -341,6 +342,24 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) goto done; } + /* + * The client specified timeout elapsed + * avoid further retries. + * + * Otherwise keep waiting either waiting + * for changes in locking.tdb or the polling + * mode timers waiting for posix locks. + */ + elapsed = timeval_elapsed(&state->endtime); + if (elapsed > 0) { + /* + * On timeout we always return + * NT_STATUS_FILE_LOCK_CONFLICT + */ + status = NT_STATUS_FILE_LOCK_CONFLICT; + goto done; + } + subreq = dbwrap_watched_watch_send( state, state->ev, lck->data->record, blocking_pid); if (tevent_req_nomem(subreq, req)) { @@ -395,17 +414,12 @@ static void smbd_smb1_do_locks_retry(struct tevent_req *subreq) DBG_DEBUG("dbwrap_watched_watch_recv returned %s\n", nt_errstr(status)); - if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { - double elapsed = timeval_elapsed(&state->endtime); - if (elapsed > 0) { - smbd_smb1_brl_finish_by_req( - req, NT_STATUS_FILE_LOCK_CONFLICT); - return; - } - /* - * This is a posix lock retry. Just retry. - */ - } + /* + * We ignore any errors here, it's most likely + * we just get NT_STATUS_OK or NT_STATUS_IO_TIMEOUT. + * + * In any case we can just give it a retry. + */ smbd_smb1_do_locks_try(req); } -- 2.17.1 From e91bae2bdb11c8466a42ae51660bb564de1aedc2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 16:44:11 +0200 Subject: [PATCH 150/376] s3:blocking: Remove bug reproducer from a few commits ago The problem is fixed, now we can revert the change that made it easier to trigger. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 62ec58b06c38ee82bb3147c4d325413fd3a76499) --- source3/smbd/blocking.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 587923aa5ec..af889a10d62 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -239,7 +239,7 @@ struct tevent_req *smbd_smb1_do_locks_send( DBG_DEBUG("Blocked on a posix lock. Retry in one second\n"); - tmp = timeval_current_ofs(15, 0); + tmp = timeval_current_ofs(1, 0); endtime = timeval_min(&endtime, &tmp); } @@ -375,7 +375,7 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) DBG_DEBUG("Blocked on a posix lock. Retry in one second\n"); - tmp = timeval_current_ofs(15, 0); + tmp = timeval_current_ofs(1, 0); endtime = timeval_min(&endtime, &tmp); } -- 2.17.1 From 1fd0a52e6727b191aa008f7a260ad748d34d5870 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 17:26:43 +0200 Subject: [PATCH 151/376] s3:blocking: use dynamic posix lock wait intervals We want to start with a short timeout (200ms) and slow down to larger timeouts up to 2s for the default value of "lock spin time". BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 15765644d2590d6549f8fcc01c39c56387eed654) --- source3/smbd/blocking.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index af889a10d62..50e1d436eb7 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -102,6 +102,7 @@ struct smbd_smb1_do_locks_state { struct smb_request *smbreq; struct files_struct *fsp; uint32_t timeout; + uint32_t polling_msecs; struct timeval endtime; bool large_offset; /* required for correct cancel */ enum brl_flavour lock_flav; @@ -115,6 +116,32 @@ static void smbd_smb1_do_locks_retry(struct tevent_req *subreq); static void smbd_smb1_blocked_locks_cleanup( struct tevent_req *req, enum tevent_req_state req_state); +static void smbd_smb1_do_locks_update_polling_msecs( + struct smbd_smb1_do_locks_state *state) +{ + /* + * The default lp_lock_spin_time() is 200ms. + * + * v_min is in the range of 0.002 to 20 secs + * (0.2 secs by default) + * + * v_max is in the range of 0.02 to 200 secs + * (2.0 secs by default) + * + * The typical steps are: + * 0.2, 0.4, 0.6, 0.8, ... 2.0 + */ + uint32_t v_min = MAX(2, MIN(20000, lp_lock_spin_time())); + uint32_t v_max = 10 * v_min; + + if (state->polling_msecs >= v_max) { + state->polling_msecs = v_max; + return; + } + + state->polling_msecs += v_min; +} + struct tevent_req *smbd_smb1_do_locks_send( TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -237,9 +264,12 @@ struct tevent_req *smbd_smb1_do_locks_send( if (blocking_smblctx == UINT64_MAX) { struct timeval tmp; - DBG_DEBUG("Blocked on a posix lock. Retry in one second\n"); + smbd_smb1_do_locks_update_polling_msecs(state); + + DBG_DEBUG("Blocked on a posix lock. Retry in %"PRIu32" msecs\n", + state->polling_msecs); - tmp = timeval_current_ofs(1, 0); + tmp = timeval_current_ofs_msec(state->polling_msecs); endtime = timeval_min(&endtime, &tmp); } @@ -373,9 +403,12 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) if (blocking_smblctx == UINT64_MAX) { struct timeval tmp; - DBG_DEBUG("Blocked on a posix lock. Retry in one second\n"); + smbd_smb1_do_locks_update_polling_msecs(state); + + DBG_DEBUG("Blocked on a posix lock. Retry in %"PRIu32" msecs\n", + state->polling_msecs); - tmp = timeval_current_ofs(1, 0); + tmp = timeval_current_ofs_msec(state->polling_msecs); endtime = timeval_min(&endtime, &tmp); } -- 2.17.1 From 85b9b5f04fdf7fa432f7260b27f77342f27dddbb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 19 Aug 2019 16:30:16 +0200 Subject: [PATCH 152/376] s4:torture/raw: assert to get LOCK_NOT_GRANTED in torture_samba3_posixtimedlock() There should not be a different if the blocker is a posix process instead of another smbd. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 2a77025a1e16d897281e5840192c93fa03328681) --- selftest/knownfail.d/samba3posixtimedlock | 1 + source4/torture/raw/samba3misc.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 selftest/knownfail.d/samba3posixtimedlock diff --git a/selftest/knownfail.d/samba3posixtimedlock b/selftest/knownfail.d/samba3posixtimedlock new file mode 100644 index 00000000000..56d2d349e1e --- /dev/null +++ b/selftest/knownfail.d/samba3posixtimedlock @@ -0,0 +1 @@ +^samba3.raw.samba3posixtimedlock.samba3posixtimedlock diff --git a/source4/torture/raw/samba3misc.c b/source4/torture/raw/samba3misc.c index dc460b9cd8b..2f484023bea 100644 --- a/source4/torture/raw/samba3misc.c +++ b/source4/torture/raw/samba3misc.c @@ -775,8 +775,8 @@ static void receive_lock_result(struct smbcli_request *req) } /* - * Check that Samba3 correctly deals with conflicting posix byte range locks - * on an underlying file + * Check that Samba3 correctly deals with conflicting local posix byte range + * locks on an underlying file via "normal" SMB1 (without unix extentions). * * Note: This test depends on "posix locking = yes". * Note: To run this test, use "--option=torture:localdir=" @@ -873,7 +873,7 @@ bool torture_samba3_posixtimedlock(struct torture_context *tctx, struct smbcli_s status = smb_raw_lock(cli->tree, &io); ret = true; - CHECK_STATUS(tctx, status, NT_STATUS_FILE_LOCK_CONFLICT); + CHECK_STATUS(tctx, status, NT_STATUS_LOCK_NOT_GRANTED); if (!ret) { goto done; -- 2.17.1 From b56bb2ac59dd190cdf3c726a7becf2ae9d296657 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 19 Aug 2019 12:04:43 +0200 Subject: [PATCH 153/376] s3:blocking: maintain state->deny_status For Windows locks we start with LOCK_NOT_GRANTED and use FILE_LOCK_CONFLICT if we retried after a timeout. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit aba0ee46258f3dd910421facb742fce3318a6946) --- selftest/knownfail.d/samba3posixtimedlock | 1 - source3/smbd/blocking.c | 33 +++++++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) delete mode 100644 selftest/knownfail.d/samba3posixtimedlock diff --git a/selftest/knownfail.d/samba3posixtimedlock b/selftest/knownfail.d/samba3posixtimedlock deleted file mode 100644 index 56d2d349e1e..00000000000 --- a/selftest/knownfail.d/samba3posixtimedlock +++ /dev/null @@ -1 +0,0 @@ -^samba3.raw.samba3posixtimedlock.samba3posixtimedlock diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 50e1d436eb7..a87d62d910a 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -109,6 +109,7 @@ struct smbd_smb1_do_locks_state { uint16_t num_locks; struct smbd_lock_element *locks; uint16_t blocker; + NTSTATUS deny_status; }; static void smbd_smb1_do_locks_try(struct tevent_req *req); @@ -176,6 +177,16 @@ struct tevent_req *smbd_smb1_do_locks_send( state->num_locks = num_locks; state->locks = locks; + if (lock_flav == POSIX_LOCK) { + /* + * SMB1 posix locks always use + * NT_STATUS_FILE_LOCK_CONFLICT. + */ + state->deny_status = NT_STATUS_FILE_LOCK_CONFLICT; + } else { + state->deny_status = NT_STATUS_LOCK_NOT_GRANTED; + } + DBG_DEBUG("state=%p, state->smbreq=%p\n", state, state->smbreq); if (num_locks == 0) { @@ -245,10 +256,19 @@ struct tevent_req *smbd_smb1_do_locks_send( state->timeout, blocking_smblctx); + /* + * If the endtime is not elapsed yet, + * it means we'll retry after a timeout. + * In that case we'll have to return + * NT_STATUS_FILE_LOCK_CONFLICT + * instead of NT_STATUS_LOCK_NOT_GRANTED. + */ if (state->timeout == 0) { + status = state->deny_status; tevent_req_nterror(req, status); goto done; } + state->deny_status = NT_STATUS_FILE_LOCK_CONFLICT; subreq = dbwrap_watched_watch_send( state, state->ev, lck->data->record, blocking_pid); @@ -379,16 +399,19 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) * Otherwise keep waiting either waiting * for changes in locking.tdb or the polling * mode timers waiting for posix locks. + * + * If the endtime is not expired yet, + * it means we'll retry after a timeout. + * In that case we'll have to return + * NT_STATUS_FILE_LOCK_CONFLICT + * instead of NT_STATUS_LOCK_NOT_GRANTED. */ elapsed = timeval_elapsed(&state->endtime); if (elapsed > 0) { - /* - * On timeout we always return - * NT_STATUS_FILE_LOCK_CONFLICT - */ - status = NT_STATUS_FILE_LOCK_CONFLICT; + status = state->deny_status; goto done; } + state->deny_status = NT_STATUS_FILE_LOCK_CONFLICT; subreq = dbwrap_watched_watch_send( state, state->ev, lck->data->record, blocking_pid); -- 2.17.1 From 8b3a50609f430ec08add2bbac77b106a585d97c6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 19 Aug 2019 12:33:28 +0200 Subject: [PATCH 154/376] s3:brlock: always return LOCK_NOT_GRANTED instead of FILE_LOCK_CONFLICT Returning NT_STATUS_FILE_LOCK_CONFLICT is a SMB1 only detail for delayed brlock requests, which is handled in smbd_smb1_do_locks*(). The brlock layer should be consistent even for posix locks. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Signed-off-by: Volker Lendecke (cherry picked from commit ad98eec6090430ba5296a5111dde2e53b9cd217a) --- source3/locking/brlock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index 628c2574357..0a85bd0b057 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -462,7 +462,7 @@ NTSTATUS brl_lock_windows_default(struct byte_range_lock *br_lck, plock->context.smblctx = 0xFFFFFFFFFFFFFFFFLL; if (errno_ret == EACCES || errno_ret == EAGAIN) { - status = NT_STATUS_FILE_LOCK_CONFLICT; + status = NT_STATUS_LOCK_NOT_GRANTED; goto fail; } else { status = map_nt_error_from_unix(errno); @@ -829,7 +829,7 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck, TALLOC_FREE(tp); /* Remember who blocked us. */ plock->context.smblctx = curr_lock->context.smblctx; - return NT_STATUS_FILE_LOCK_CONFLICT; + return NT_STATUS_LOCK_NOT_GRANTED; } /* Just copy the Windows lock into the new array. */ memcpy(&tp[count], curr_lock, sizeof(struct lock_struct)); @@ -849,7 +849,7 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck, TALLOC_FREE(tp); /* Remember who blocked us. */ plock->context.smblctx = curr_lock->context.smblctx; - return NT_STATUS_FILE_LOCK_CONFLICT; + return NT_STATUS_LOCK_NOT_GRANTED; } /* Work out overlaps. */ @@ -912,7 +912,7 @@ static NTSTATUS brl_lock_posix(struct byte_range_lock *br_lck, if (errno_ret == EACCES || errno_ret == EAGAIN) { TALLOC_FREE(tp); - status = NT_STATUS_FILE_LOCK_CONFLICT; + status = NT_STATUS_LOCK_NOT_GRANTED; goto fail; } else { TALLOC_FREE(tp); -- 2.17.1 From e5385142987202a67fc3667506ee233f2c726107 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2019 16:14:23 +0200 Subject: [PATCH 155/376] s3:smb2_lock: move from 'blocking' to 'state->blocking' This will simplify the next commits. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit f13d13ae9da3072862a781bc926e7a06e8384337) --- source3/smbd/smb2_lock.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index e9c8d7f890e..4cf735ff48d 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -42,6 +42,7 @@ struct smbd_smb2_lock_state { struct smbd_smb2_request *smb2req; struct smb_request *smb1req; struct files_struct *fsp; + bool blocking; uint16_t lock_count; struct smbd_lock_element *locks; }; @@ -200,7 +201,6 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req; struct smbd_smb2_lock_state *state; - bool blocking = false; bool isunlock = false; uint16_t i; struct smbd_lock_element *locks; @@ -241,7 +241,7 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); return tevent_req_post(req, ev); } - blocking = true; + state->blocking = true; break; case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY: @@ -383,7 +383,7 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - if (blocking && + if (state->blocking && (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED) || NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT))) { struct tevent_req *subreq; -- 2.17.1 From 5e156be97a37b9bd42b18a78cf6ab541271971e7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2019 16:39:41 +0200 Subject: [PATCH 156/376] s3:smb2_lock: split smbd_smb2_lock_retry() into _try() and _retry() This makes it possible to reuse _try() in the _send() function in the next commits. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit d096742da1a045357f52ccd5b28d499c30e96152) --- source3/smbd/smb2_lock.c | 49 ++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 4cf735ff48d..c2b4603f3e1 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -189,6 +189,7 @@ static void smbd_smb2_request_lock_done(struct tevent_req *subreq) } } +static void smbd_smb2_lock_try(struct tevent_req *req); static void smbd_smb2_lock_retry(struct tevent_req *subreq); static bool smbd_smb2_lock_cancel(struct tevent_req *req); @@ -410,10 +411,8 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } -static void smbd_smb2_lock_retry(struct tevent_req *subreq) +static void smbd_smb2_lock_try(struct tevent_req *req) { - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); struct smbd_smb2_lock_state *state = tevent_req_data( req, struct smbd_smb2_lock_state); struct share_mode_lock *lck = NULL; @@ -421,22 +420,7 @@ static void smbd_smb2_lock_retry(struct tevent_req *subreq) struct server_id blocking_pid = { 0 }; uint64_t blocking_smblctx; NTSTATUS status; - bool ok; - - /* - * Make sure we run as the user again - */ - ok = change_to_user_by_fsp(state->fsp); - if (!ok) { - tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); - return; - } - - status = dbwrap_watched_watch_recv(subreq, NULL, NULL); - TALLOC_FREE(subreq); - if (tevent_req_nterror(req, status)) { - return; - } + struct tevent_req *subreq = NULL; lck = get_existing_share_mode_lock( talloc_tos(), state->fsp->file_id); @@ -467,6 +451,33 @@ static void smbd_smb2_lock_retry(struct tevent_req *subreq) tevent_req_set_callback(subreq, smbd_smb2_lock_retry, req); } +static void smbd_smb2_lock_retry(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct smbd_smb2_lock_state *state = tevent_req_data( + req, struct smbd_smb2_lock_state); + NTSTATUS status; + bool ok; + + /* + * Make sure we run as the user again + */ + ok = change_to_user_by_fsp(state->fsp); + if (!ok) { + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; + } + + status = dbwrap_watched_watch_recv(subreq, NULL, NULL); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + smbd_smb2_lock_try(req); +} + static NTSTATUS smbd_smb2_lock_recv(struct tevent_req *req) { return tevent_req_simple_recv_ntstatus(req); -- 2.17.1 From c4ab0c8502284ee0a4e4336f42c352b5a19dda43 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2019 16:39:41 +0200 Subject: [PATCH 157/376] s3:smb2_lock: error out early in smbd_smb2_lock_send() We no longer expect NT_STATUS_FILE_LOCK_CONFLICT from the VFS layer and assert that in a future version. This makes it easier to port the same logic to smbd_smb2_lock_try(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 39d514cdc358f175d0968f4a78f8f2f05a6c1707) --- source3/smbd/smb2_lock.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index c2b4603f3e1..c049c33ebbc 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -383,10 +383,26 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, tevent_req_done(req); return tevent_req_post(req, ev); } + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { + /* + * This is a bug and will be changed into an assert + * in a future version. We should only + * ever get NT_STATUS_LOCK_NOT_GRANTED here! + */ + static uint64_t _bug_count; + int _level = (_bug_count++ == 0) ? DBGLVL_ERR: DBGLVL_DEBUG; + DBG_PREFIX(_level, ("BUG: Got %s mapping to " + "NT_STATUS_LOCK_NOT_GRANTED\n", + nt_errstr(status))); + status = NT_STATUS_LOCK_NOT_GRANTED; + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { + TALLOC_FREE(lck); + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); + } - if (state->blocking && - (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED) || - NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT))) { + if (state->blocking) { struct tevent_req *subreq; DBG_DEBUG("Watching share mode lock\n"); -- 2.17.1 From 1fb82e04d0231392a9243b6b924e6c1765110a8d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2019 16:39:41 +0200 Subject: [PATCH 158/376] s3:smb2_lock: let smbd_smb2_lock_try() explicitly check for the retry condition This makes it possible to reuse _try() in the _send() function in the next commit. We should not retry forever on a hard error. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 7f77e0b4e9878f1f3515206d052adc012e26aafb) --- source3/smbd/smb2_lock.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index c049c33ebbc..153705b26a1 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -457,6 +457,32 @@ static void smbd_smb2_lock_try(struct tevent_req *req) tevent_req_done(req); return; } + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { + /* + * This is a bug and will be changed into an assert + * in future version. We should only + * ever get NT_STATUS_LOCK_NOT_GRANTED here! + */ + static uint64_t _bug_count; + int _level = (_bug_count++ == 0) ? DBGLVL_ERR: DBGLVL_DEBUG; + DBG_PREFIX(_level, ("BUG: Got %s mapping to " + "NT_STATUS_LOCK_NOT_GRANTED\n", + nt_errstr(status))); + status = NT_STATUS_LOCK_NOT_GRANTED; + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { + TALLOC_FREE(lck); + tevent_req_nterror(req, status); + return; + } + + if (!state->blocking) { + TALLOC_FREE(lck); + tevent_req_nterror(req, status); + return; + } + + DBG_DEBUG("Watching share mode lock\n"); subreq = dbwrap_watched_watch_send( state, state->ev, lck->data->record, blocking_pid); -- 2.17.1 From 00fc583960f0983c84f960408c8cc92c25c0a928 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2019 16:39:41 +0200 Subject: [PATCH 159/376] s3:smb2_lock: make use of smbd_smb2_lock_try() in smbd_smb2_lock_send() We only need the logic to call smbd_do_locks_try() and a possible retry once in smbd_smb2_lock_try(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher (cherry picked from commit 359e9992be713bbecfdb19998d69e1d3f020c5e9) --- source3/smbd/smb2_lock.c | 68 ++++------------------------------------ 1 file changed, 6 insertions(+), 62 deletions(-) diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 153705b26a1..a8ccf21cc20 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -205,10 +205,6 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, bool isunlock = false; uint16_t i; struct smbd_lock_element *locks; - struct share_mode_lock *lck = NULL; - uint16_t blocker_idx; - struct server_id blocking_pid = { 0 }; - uint64_t blocking_smblctx; NTSTATUS status; req = tevent_req_create(mem_ctx, &state, @@ -363,68 +359,16 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - lck = get_existing_share_mode_lock( - talloc_tos(), state->fsp->file_id); - if (tevent_req_nomem(lck, req)) { - return tevent_req_post(req, ev); - } - - status = smbd_do_locks_try( - state->fsp, - WINDOWS_LOCK, - state->lock_count, - state->locks, - &blocker_idx, - &blocking_pid, - &blocking_smblctx); - - if (NT_STATUS_IS_OK(status)) { - TALLOC_FREE(lck); - tevent_req_done(req); - return tevent_req_post(req, ev); - } - if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { - /* - * This is a bug and will be changed into an assert - * in a future version. We should only - * ever get NT_STATUS_LOCK_NOT_GRANTED here! - */ - static uint64_t _bug_count; - int _level = (_bug_count++ == 0) ? DBGLVL_ERR: DBGLVL_DEBUG; - DBG_PREFIX(_level, ("BUG: Got %s mapping to " - "NT_STATUS_LOCK_NOT_GRANTED\n", - nt_errstr(status))); - status = NT_STATUS_LOCK_NOT_GRANTED; - } - if (!NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { - TALLOC_FREE(lck); - tevent_req_nterror(req, status); + smbd_smb2_lock_try(req); + if (!tevent_req_is_in_progress(req)) { return tevent_req_post(req, ev); } - if (state->blocking) { - struct tevent_req *subreq; - - DBG_DEBUG("Watching share mode lock\n"); - - subreq = dbwrap_watched_watch_send( - state, state->ev, lck->data->record, blocking_pid); - TALLOC_FREE(lck); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, smbd_smb2_lock_retry, req); - - tevent_req_defer_callback(req, smb2req->sconn->ev_ctx); - aio_add_req_to_fsp(state->fsp, req); - tevent_req_set_cancel_fn(req, smbd_smb2_lock_cancel); + tevent_req_defer_callback(req, smb2req->sconn->ev_ctx); + aio_add_req_to_fsp(state->fsp, req); + tevent_req_set_cancel_fn(req, smbd_smb2_lock_cancel); - return req; - } - - TALLOC_FREE(lck); - tevent_req_nterror(req, status); - return tevent_req_post(req, ev); + return req; } static void smbd_smb2_lock_try(struct tevent_req *req) -- 2.17.1 From 061b60353d76ac368f7e48df9fe7fb899f7a2642 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 19 Aug 2019 17:38:30 +0200 Subject: [PATCH 160/376] s4:torture/smb2: add smb2.samba3misc.localposixlock1 This demonstrates that the SMB2 code path doesn't do any retry for local posix locks. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 7155d3a2c5d7237f00cccb1802c1341cf295864e) --- selftest/knownfail.d/smb2.localposixlock | 1 + selftest/skip | 1 + source3/selftest/tests.py | 2 +- source4/torture/smb2/samba3misc.c | 188 +++++++++++++++++++++++ source4/torture/smb2/smb2.c | 1 + source4/torture/smb2/wscript_build | 1 + 6 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 selftest/knownfail.d/smb2.localposixlock create mode 100644 source4/torture/smb2/samba3misc.c diff --git a/selftest/knownfail.d/smb2.localposixlock b/selftest/knownfail.d/smb2.localposixlock new file mode 100644 index 00000000000..1b84f074e0b --- /dev/null +++ b/selftest/knownfail.d/smb2.localposixlock @@ -0,0 +1 @@ +^samba3.smb2.samba3misc.localposixlock1 diff --git a/selftest/skip b/selftest/skip index c471072e88f..11bf29599fa 100644 --- a/selftest/skip +++ b/selftest/skip @@ -93,6 +93,7 @@ ^samba4.rpc.samr.passwords.*ncacn_np\(ad_dc_slowtests\) # currently fails, possibly config issue ^samba4.rpc.samr.passwords.*s4member # currently fails, possibly config issue ^samba4.raw.scan.eamax +^samba4.smb2.samba3misc ^samba4.smb2.notify ^samba4.smb2.scan ^samba4.smb2.lease diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index a3daeacae6b..ebc366de3ea 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -529,7 +529,7 @@ for t in tests: plansmbtorture4testsuite(t, env, '//$SERVER/tmp -k yes -U$DC_USERNAME@$REALM%$DC_PASSWORD --option=torture:addc=$DC_SERVER', description='kerberos connection') plansmbtorture4testsuite(t, env, '//$SERVER/tmpguest -U% --option=torture:addc=$DC_SERVER', description='anonymous connection') plansmbtorture4testsuite(t, env, '//$SERVER/tmp -k no -U$DC_USERNAME@$REALM%$DC_PASSWORD', description='ntlm user@realm') - elif t == "raw.samba3posixtimedlock": + elif t == "raw.samba3posixtimedlock" or t == "smb2.samba3misc": plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share') plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/ad_dc/share') elif t == "raw.chkpath": diff --git a/source4/torture/smb2/samba3misc.c b/source4/torture/smb2/samba3misc.c new file mode 100644 index 00000000000..a5fe6c1bbea --- /dev/null +++ b/source4/torture/smb2/samba3misc.c @@ -0,0 +1,188 @@ +/* + Unix SMB/CIFS implementation. + + Test some misc Samba3 code paths + + Copyright (C) Volker Lendecke 2006 + Copyright (C) Stefan Metzmacher 2019 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "system/time.h" +#include "system/filesys.h" +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "../libcli/smb/smbXcli_base.h" +#include "torture/torture.h" +#include "torture/smb2/proto.h" +#include "torture/util.h" +#include "lib/events/events.h" +#include "param/param.h" + +#define CHECK_STATUS(status, correct) do { \ + const char *_cmt = "(" __location__ ")"; \ + torture_assert_ntstatus_equal_goto(tctx,status,correct, \ + ret,done,_cmt); \ + } while (0) + +#define BASEDIR "samba3misc.smb2" + +#define WAIT_FOR_ASYNC_RESPONSE(req) \ + while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \ + if (tevent_loop_once(tctx->ev) != 0) { \ + break; \ + } \ + } + +static void torture_smb2_tree_disconnect_timer(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval now, + void *private_data) +{ + struct smb2_tree *tree = + talloc_get_type_abort(private_data, + struct smb2_tree); + + smbXcli_conn_disconnect(tree->session->transport->conn, + NT_STATUS_CTX_CLIENT_QUERY_TIMEOUT); +} + +/* + * Check that Samba3 correctly deals with conflicting local posix byte range + * locks on an underlying file via "normal" SMB2 (without posix extentions). + * + * Note: This test depends on "posix locking = yes". + * Note: To run this test, use "--option=torture:localdir=" + */ +static bool torture_samba3_localposixlock1(struct torture_context *tctx, + struct smb2_tree *tree) +{ + NTSTATUS status; + bool ret = true; + int rc; + const char *fname = "posixtimedlock.dat"; + const char *fpath; + const char *localdir; + const char *localname; + struct smb2_handle h = {{0}}; + struct smb2_lock lck = {0}; + struct smb2_lock_element el[1] = {{0}}; + struct smb2_request *req = NULL; + int fd = -1; + struct flock posix_lock; + struct tevent_timer *te; + + status = torture_smb2_testdir(tree, BASEDIR, &h); + CHECK_STATUS(status, NT_STATUS_OK); + smb2_util_close(tree, h); + + status = torture_smb2_testfile(tree, fname, &h); + CHECK_STATUS(status, NT_STATUS_OK); + + fpath = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fname); + torture_assert(tctx, fpath != NULL, "fpath\n"); + + status = torture_smb2_testfile(tree, fpath, &h); + CHECK_STATUS(status, NT_STATUS_OK); + + localdir = torture_setting_string(tctx, "localdir", NULL); + torture_assert(tctx, localdir != NULL, + "--option=torture:localdir= required\n"); + + localname = talloc_asprintf(tctx, "%s/%s/%s", + localdir, BASEDIR, fname); + torture_assert(tctx, localname != NULL, "localname\n"); + + /* + * Lock a byte range from posix + */ + + torture_comment(tctx, " local open(%s)\n", localname); + fd = open(localname, O_RDWR); + if (fd == -1) { + torture_warning(tctx, "open(%s) failed: %s\n", + localname, strerror(errno)); + torture_assert(tctx, fd != -1, "open localname\n"); + } + + posix_lock.l_type = F_WRLCK; + posix_lock.l_whence = SEEK_SET; + posix_lock.l_start = 0; + posix_lock.l_len = 1; + + torture_comment(tctx, " local fcntl\n"); + rc = fcntl(fd, F_SETLK, &posix_lock); + if (rc == -1) { + torture_warning(tctx, "fcntl failed: %s\n", strerror(errno)); + torture_assert(tctx, rc != -1, "fcntl lock\n"); + } + + el[0].offset = 0; + el[0].length = 1; + el[0].reserved = 0x00000000; + el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE | + SMB2_LOCK_FLAG_FAIL_IMMEDIATELY; + lck.in.locks = el; + lck.in.lock_count = 0x0001; + lck.in.lock_sequence = 0x00000000; + lck.in.file.handle = h; + + torture_comment(tctx, " remote non-blocking lock\n"); + status = smb2_lock(tree, &lck); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + torture_comment(tctx, " remote async blocking lock\n"); + el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE; + req = smb2_lock_send(tree, &lck); + torture_assert(tctx, req != NULL, "smb2_lock_send()\n"); + + te = tevent_add_timer(tctx->ev, + tctx, timeval_current_ofs(5, 0), + torture_smb2_tree_disconnect_timer, + tree); + torture_assert(tctx, te != NULL, "tevent_add_timer\n"); + + torture_comment(tctx, " remote wait for STATUS_PENDING\n"); + WAIT_FOR_ASYNC_RESPONSE(req); + + torture_comment(tctx, " local close file\n"); + close(fd); + fd = -1; + + torture_comment(tctx, " remote lock should now succeed\n"); + status = smb2_lock_recv(req, &lck); + CHECK_STATUS(status, NT_STATUS_OK); + +done: + if (fd != -1) { + close(fd); + } + smb2_util_close(tree, h); + smb2_deltree(tree, BASEDIR); + return ret; +} + +struct torture_suite *torture_smb2_samba3misc_init(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create(ctx, "samba3misc"); + + torture_suite_add_1smb2_test(suite, "localposixlock1", + torture_samba3_localposixlock1); + + suite->description = talloc_strdup(suite, "SMB2 Samba3 MISC"); + + return suite; +} diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c index f495c19d251..e57dba3c1d9 100644 --- a/source4/torture/smb2/smb2.c +++ b/source4/torture/smb2/smb2.c @@ -195,6 +195,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx) torture_suite_add_suite(suite, torture_smb2_doc_init(suite)); torture_suite_add_suite(suite, torture_smb2_multichannel_init(suite)); + torture_suite_add_suite(suite, torture_smb2_samba3misc_init(suite)); suite->description = talloc_strdup(suite, "SMB2-specific tests"); diff --git a/source4/torture/smb2/wscript_build b/source4/torture/smb2/wscript_build index e605a4589ac..8b17cfb36d4 100644 --- a/source4/torture/smb2/wscript_build +++ b/source4/torture/smb2/wscript_build @@ -34,6 +34,7 @@ bld.SAMBA_MODULE('TORTURE_SMB2', sharemode.c smb2.c streams.c + samba3misc.c util.c ''', subsystem='smbtorture', -- 2.17.1 From c4d7c186aca3b9fb42354ac47f10514468b4c8b7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 2 Aug 2019 14:50:27 +0200 Subject: [PATCH 161/376] s3:smb2_lock: add retry for POSIX locks BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 8decf41bbb8be2b4ac463eb6ace16a8628276ab5) --- selftest/knownfail.d/smb2.localposixlock | 1 - source3/smbd/smb2_lock.c | 55 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) delete mode 100644 selftest/knownfail.d/smb2.localposixlock diff --git a/selftest/knownfail.d/smb2.localposixlock b/selftest/knownfail.d/smb2.localposixlock deleted file mode 100644 index 1b84f074e0b..00000000000 --- a/selftest/knownfail.d/smb2.localposixlock +++ /dev/null @@ -1 +0,0 @@ -^samba3.smb2.samba3misc.localposixlock1 diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index a8ccf21cc20..8ba54fe6995 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -43,6 +43,7 @@ struct smbd_smb2_lock_state { struct smb_request *smb1req; struct files_struct *fsp; bool blocking; + uint32_t polling_msecs; uint16_t lock_count; struct smbd_lock_element *locks; }; @@ -371,6 +372,32 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return req; } +static void smbd_smb2_lock_update_polling_msecs( + struct smbd_smb2_lock_state *state) +{ + /* + * The default lp_lock_spin_time() is 200ms. + * + * v_min is in the range of 0.002 to 20 secs + * (0.2 secs by default) + * + * v_max is in the range of 0.02 to 200 secs + * (2.0 secs by default) + * + * The typical steps are: + * 0.2, 0.4, 0.6, 0.8, ... 2.0 + */ + uint32_t v_min = MAX(2, MIN(20000, lp_lock_spin_time())); + uint32_t v_max = 10 * v_min; + + if (state->polling_msecs >= v_max) { + state->polling_msecs = v_max; + return; + } + + state->polling_msecs += v_min; +} + static void smbd_smb2_lock_try(struct tevent_req *req) { struct smbd_smb2_lock_state *state = tevent_req_data( @@ -381,6 +408,7 @@ static void smbd_smb2_lock_try(struct tevent_req *req) uint64_t blocking_smblctx; NTSTATUS status; struct tevent_req *subreq = NULL; + struct timeval endtime = { 0 }; lck = get_existing_share_mode_lock( talloc_tos(), state->fsp->file_id); @@ -426,6 +454,15 @@ static void smbd_smb2_lock_try(struct tevent_req *req) return; } + if (blocking_smblctx == UINT64_MAX) { + smbd_smb2_lock_update_polling_msecs(state); + + DBG_DEBUG("Blocked on a posix lock. Retry in %"PRIu32" msecs\n", + state->polling_msecs); + + endtime = timeval_current_ofs_msec(state->polling_msecs); + } + DBG_DEBUG("Watching share mode lock\n"); subreq = dbwrap_watched_watch_send( @@ -435,6 +472,18 @@ static void smbd_smb2_lock_try(struct tevent_req *req) return; } tevent_req_set_callback(subreq, smbd_smb2_lock_retry, req); + + if (!timeval_is_zero(&endtime)) { + bool ok; + + ok = tevent_req_set_endtime(subreq, + state->ev, + endtime); + if (!ok) { + tevent_req_oom(req); + return; + } + } } static void smbd_smb2_lock_retry(struct tevent_req *subreq) @@ -457,6 +506,12 @@ static void smbd_smb2_lock_retry(struct tevent_req *subreq) status = dbwrap_watched_watch_recv(subreq, NULL, NULL); TALLOC_FREE(subreq); + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + /* + * This is just a trigger for a timed retry. + */ + status = NT_STATUS_OK; + } if (tevent_req_nterror(req, status)) { return; } -- 2.17.1 From da765a062aa4b57814ea426c94c6b3ba23dca47c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 16 Aug 2019 12:28:39 +0200 Subject: [PATCH 162/376] s4:torture/raw: improvements for multilock2 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 8a7039be530adcdda9e7e7621bdcf902f5ca1721) --- source4/torture/raw/lock.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c index f1fbdd6da71..f264d0aea11 100644 --- a/source4/torture/raw/lock.c +++ b/source4/torture/raw/lock.c @@ -2449,7 +2449,7 @@ static bool test_multilock2(struct torture_context *tctx, lock[0].pid = cli->session->pid+2; io.lockx.in.lock_cnt = 1; req2 = smb_raw_lock_send(cli->tree, &io); - torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, + torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx, "Failed to setup timed locks (%s)\n", __location__)); /* Unlock lock[0] */ @@ -2465,6 +2465,9 @@ static bool test_multilock2(struct torture_context *tctx, status = smbcli_request_simple_recv(req2); CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + /* Start the clock. */ t = time_mono(NULL); -- 2.17.1 From 6bd411aad81477637255fcb5c826ddaf43f593b1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 16 Aug 2019 12:13:15 +0200 Subject: [PATCH 163/376] s4:torture/raw: add multilock3 test This demonstrates that unrelated lock ranges are not blocked by other blocked requests on the same fsp. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 297763c6b618c07148d788b46218a0798225bf79) --- selftest/knownfail.d/multilock | 1 + source4/torture/raw/lock.c | 266 +++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100644 selftest/knownfail.d/multilock diff --git a/selftest/knownfail.d/multilock b/selftest/knownfail.d/multilock new file mode 100644 index 00000000000..e0e6e81c453 --- /dev/null +++ b/selftest/knownfail.d/multilock @@ -0,0 +1 @@ +^samba3.raw.lock.multilock3.*nt4_dc diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c index f264d0aea11..bea55f6a605 100644 --- a/source4/torture/raw/lock.c +++ b/source4/torture/raw/lock.c @@ -2494,6 +2494,271 @@ done: return ret; } +/* + test multi3 Locking&X operation + This test is designed to show that + lock precedence on the server is based + on the order received, not on the ability + to grant. + + Compared to test_multilock2() (above) + this test demonstrates that completely + unrelated ranges work independently. + + For example: + + A blocked lock request containing 2 locks + will be satified before a subsequent blocked + lock request over one of the same regions, + even if that region is then unlocked. But + a lock of a different region goes through. E.g. + + All locks are LOCKING_ANDX_EXCLUSIVE_LOCK (rw). + + (a) lock 100->109, 120->129 (granted) + (b) lock 100->109, 120->129 (blocks, timeout=20s) + (c) lock 100->109 (blocks, timeout=2s) + (d) lock 110->119 (granted) + (e) lock 110->119 (blocks, timeout=20s) + (f) unlock 100->109 (a) + (g) lock 100->109 (not granted, blocked by (b)) + (h) lock 100->109 (not granted, blocked by itself (b)) + (i) lock (c) will not be granted(conflict, times out) + as lock (b) will take precedence. + (j) unlock 110-119 (d) + (k) lock (e) completes and is not blocked by (a) nor (b) + (l) lock 100->109 (not granted(conflict), blocked by (b)) + (m) lock 100->109 (not granted(conflict), blocked by itself (b)) + (n) unlock 120-129 (a) + (o) lock (b) completes +*/ +static bool test_multilock3(struct torture_context *tctx, + struct smbcli_state *cli) +{ + union smb_lock io; + struct smb_lock_entry lock[2]; + union smb_lock io3; + struct smb_lock_entry lock3[1]; + NTSTATUS status; + bool ret = true; + int fnum; + const char *fname = BASEDIR "\\multilock3_test.txt"; + time_t t; + struct smbcli_request *req = NULL; + struct smbcli_request *req2 = NULL; + struct smbcli_request *req4 = NULL; + + torture_assert(tctx, torture_setup_dir(cli, BASEDIR), + "Failed to setup up test directory: " BASEDIR); + + torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 3\n"); + io.generic.level = RAW_LOCK_LOCKX; + + /* Create the test file. */ + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, + "Failed to create %s - %s\n", + fname, smbcli_errstr(cli->tree))); + + /* + * a) + * Lock regions 100->109, 120->129 as + * two separate write locks in one request. + */ + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 2; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + lock[1].pid = cli->session->pid; + lock[1].offset = 120; + lock[1].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * b) + * Now request the same locks on a different + * context as blocking locks. + */ + io.lockx.in.timeout = 20000; + lock[0].pid = cli->session->pid+1; + lock[1].pid = cli->session->pid+1; + req = smb_raw_lock_send(cli->tree, &io); + torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * c) + * Request the first lock again on a separate context. + * Wait 2 seconds. This should time out (the previous + * multi-lock request should take precedence). + */ + io.lockx.in.timeout = 2000; + lock[0].pid = cli->session->pid+2; + io.lockx.in.lock_cnt = 1; + req2 = smb_raw_lock_send(cli->tree, &io); + torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * d) + * Lock regions 110->119 + */ + io3.lockx.level = RAW_LOCK_LOCKX; + io3.lockx.in.file.fnum = fnum; + io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io3.lockx.in.timeout = 0; + io3.lockx.in.ulock_cnt = 0; + io3.lockx.in.lock_cnt = 1; + io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock3[0].pid = cli->session->pid+3; + lock3[0].offset = 110; + lock3[0].count = 10; + io3.lockx.in.locks = &lock3[0]; + status = smb_raw_lock(cli->tree, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * e) + * try 110-119 again + */ + io3.lockx.in.timeout = 20000; + lock3[0].pid = cli->session->pid+4; + req4 = smb_raw_lock_send(cli->tree, &io3); + torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * f) + * Unlock (a) lock[0] 100-109 + */ + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lock[0]; + lock[0].pid = cli->session->pid; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * g) + * try to lock lock[0] 100-109 again + */ + lock[0].pid = cli->session->pid+5; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + /* + * h) + * try to lock lock[0] 100-109 again with + * the pid that's still waiting + */ + lock[0].pid = cli->session->pid+1; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV, + "req2 should still wait"); + + /* + * i) + * Did the second lock complete (should time out) ? + */ + status = smbcli_request_simple_recv(req2); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV, + "req4 should still wait"); + + /* + * j) + * Unlock (d) lock[0] 110-119 + */ + io3.lockx.in.timeout = 0; + io3.lockx.in.ulock_cnt = 1; + io3.lockx.in.lock_cnt = 0; + lock3[0].pid = cli->session->pid+3; + status = smb_raw_lock(cli->tree, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * k) + * receive the successful blocked lock request (e) + * on 110-119 while the 100-109/120-129 is still waiting. + */ + status = smbcli_request_simple_recv(req4); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * l) + * try to lock lock[0] 100-109 again + */ + lock[0].pid = cli->session->pid+6; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + + /* + * m) + * try to lock lock[0] 100-109 again with + * the pid that's still waiting + */ + lock[0].pid = cli->session->pid+1; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + + /* Start the clock. */ + t = time_mono(NULL); + + /* + * n) + * Unlock lock[1] 120-129 */ + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lock[1]; + lock[1].pid = cli->session->pid; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * o) + * receive the successful blocked lock request (b) + */ + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Fail if this took more than 2 seconds. */ + torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx, + "Blocking locks were not granted immediately (%s)\n", + __location__)); +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} /* basic testing of lock calls @@ -2517,6 +2782,7 @@ struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx) torture_suite_add_1smb_test(suite, "zerobyteread", test_zerobyteread); torture_suite_add_1smb_test(suite, "multilock", test_multilock); torture_suite_add_1smb_test(suite, "multilock2", test_multilock2); + torture_suite_add_1smb_test(suite, "multilock3", test_multilock3); return suite; } -- 2.17.1 From cc9afc3dac2fd680fd5731160889fc39eb0e360c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 16 Aug 2019 14:49:29 +0200 Subject: [PATCH 164/376] s4:torture/raw: add multilock4 test This is similar to multilock3, but uses read-only (LOCKING_ANDX_SHARED_LOCK) locks for the blocked requests. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit d3e65ceb1ec25c7b62a7e908506126269011f30d) --- selftest/knownfail.d/multilock | 1 + source4/torture/raw/lock.c | 266 +++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) diff --git a/selftest/knownfail.d/multilock b/selftest/knownfail.d/multilock index e0e6e81c453..01538acc5a8 100644 --- a/selftest/knownfail.d/multilock +++ b/selftest/knownfail.d/multilock @@ -1 +1,2 @@ ^samba3.raw.lock.multilock3.*nt4_dc +^samba3.raw.lock.multilock4.*nt4_dc diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c index bea55f6a605..26339f9b28b 100644 --- a/source4/torture/raw/lock.c +++ b/source4/torture/raw/lock.c @@ -2760,6 +2760,271 @@ done: return ret; } +/* + test multi4 Locking&X operation + This test is designed to show that + lock precedence on the server is based + on the order received, not on the ability + to grant. + + Compared to test_multilock3() (above) + this test demonstrates that pending read-only/shared + locks doesn't block shared locks others. + + The outstanding requests build an implicit + database that's checked before checking + the already granted locks in the real database. + + For example: + + A blocked read-lock request containing 2 locks + will be still be blocked, while one region + is still write-locked. While it doesn't block + other read-lock requests for the other region. E.g. + + (a) lock(rw) 100->109, 120->129 (granted) + (b) lock(ro) 100->109, 120->129 (blocks, timeout=20s) + (c) lock(ro) 100->109 (blocks, timeout=MAX) + (d) lock(rw) 110->119 (granted) + (e) lock(rw) 110->119 (blocks, timeout=20s) + (f) unlock 100->109 (a) + (g) lock(ro) (c) completes and is not blocked by (a) nor (b) + (h) lock(rw) 100->109 (not granted, blocked by (c)) + (i) lock(rw) 100->109 (pid (b)) (not granted(conflict), blocked by (c)) + (j) unlock 110-119 + (k) lock (e) completes and is not blocked by (a) nor (b) + (l) lock 100->109 (not granted(conflict), blocked by (b)) + (m) lock 100->109 (pid (b)) (not granted(conflict), blocked by itself (b)) + (n) unlock 120-129 (a) + (o) lock (b) completes +*/ +static bool test_multilock4(struct torture_context *tctx, + struct smbcli_state *cli) +{ + union smb_lock io; + struct smb_lock_entry lock[2]; + union smb_lock io3; + struct smb_lock_entry lock3[1]; + NTSTATUS status; + bool ret = true; + int fnum; + const char *fname = BASEDIR "\\multilock4_test.txt"; + time_t t; + struct smbcli_request *req = NULL; + struct smbcli_request *req2 = NULL; + struct smbcli_request *req4 = NULL; + + torture_assert(tctx, torture_setup_dir(cli, BASEDIR), + "Failed to setup up test directory: " BASEDIR); + + torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 4\n"); + io.generic.level = RAW_LOCK_LOCKX; + + /* Create the test file. */ + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, + "Failed to create %s - %s\n", + fname, smbcli_errstr(cli->tree))); + + /* + * a) + * Lock regions 100->109, 120->129 as + * two separate write locks in one request. + */ + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 2; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + lock[1].pid = cli->session->pid; + lock[1].offset = 120; + lock[1].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * b) + * Now request the same locks on a different + * context as blocking locks. But readonly. + */ + io.lockx.in.timeout = 20000; + io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; + lock[0].pid = cli->session->pid+1; + lock[1].pid = cli->session->pid+1; + req = smb_raw_lock_send(cli->tree, &io); + torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * c) + * Request the first lock again on a separate context. + * Wait forever. The previous multi-lock request (b) + * should take precedence. Also readonly. + */ + io.lockx.in.timeout = UINT32_MAX; + lock[0].pid = cli->session->pid+2; + io.lockx.in.lock_cnt = 1; + req2 = smb_raw_lock_send(cli->tree, &io); + torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * d) + * Lock regions 110->119 + */ + io3.lockx.level = RAW_LOCK_LOCKX; + io3.lockx.in.file.fnum = fnum; + io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io3.lockx.in.timeout = 0; + io3.lockx.in.ulock_cnt = 0; + io3.lockx.in.lock_cnt = 1; + io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock3[0].pid = cli->session->pid+3; + lock3[0].offset = 110; + lock3[0].count = 10; + io3.lockx.in.locks = &lock3[0]; + status = smb_raw_lock(cli->tree, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * e) + * try 110-119 again + */ + io3.lockx.in.timeout = 20000; + lock3[0].pid = cli->session->pid+4; + req4 = smb_raw_lock_send(cli->tree, &io3); + torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * f) + * Unlock (a) lock[0] 100-109 + */ + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lock[0]; + lock[0].pid = cli->session->pid; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * g) + * receive the successful blocked lock request (c) + * on 110-119 while (b) 100-109/120-129 is still waiting. + */ + status = smbcli_request_simple_recv(req2); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * h) + * try to lock lock[0] 100-109 again + * (read/write) + */ + lock[0].pid = cli->session->pid+5; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + /* + * i) + * try to lock lock[0] 100-109 again with the pid (b) + * that's still waiting. + */ + lock[0].pid = cli->session->pid+1; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV, + "req4 should still wait"); + + /* + * j) + * Unlock (d) lock[0] 110-119 + */ + io3.lockx.in.timeout = 0; + io3.lockx.in.ulock_cnt = 1; + io3.lockx.in.lock_cnt = 0; + lock3[0].pid = cli->session->pid+3; + status = smb_raw_lock(cli->tree, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * k) + * receive the successful blocked + * lock request (e) on 110-119. + */ + status = smbcli_request_simple_recv(req4); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * l) + * try to lock lock[0] 100-109 again + */ + lock[0].pid = cli->session->pid+6; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* + * m) + * try to lock lock[0] 100-109 again with the pid (b) + * that's still waiting + */ + lock[0].pid = cli->session->pid+1; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + + /* Start the clock. */ + t = time_mono(NULL); + + /* + * n) + * Unlock (a) lock[1] 120-129 + */ + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lock[1]; + lock[1].pid = cli->session->pid; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * o) + * receive the successful blocked lock request (b) + */ + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Fail if this took more than 2 seconds. */ + torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx, + "Blocking locks were not granted immediately (%s)\n", + __location__)); +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + /* basic testing of lock calls */ @@ -2783,6 +3048,7 @@ struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx) torture_suite_add_1smb_test(suite, "multilock", test_multilock); torture_suite_add_1smb_test(suite, "multilock2", test_multilock2); torture_suite_add_1smb_test(suite, "multilock3", test_multilock3); + torture_suite_add_1smb_test(suite, "multilock4", test_multilock4); return suite; } -- 2.17.1 From a037ebbc34795de46196ff50ad439356056fe082 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 16 Aug 2019 15:12:01 +0200 Subject: [PATCH 165/376] s4:torture/raw: add multilock5 test This is similar to multilock3, but uses a read-only (LOCKING_ANDX_SHARED_LOCK) locks for the first lock request. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 6d4296aca0c9a9287c0c78c8f8847a560bd2ea24) --- selftest/knownfail.d/multilock | 1 + source4/torture/raw/lock.c | 269 +++++++++++++++++++++++++++++++++ 2 files changed, 270 insertions(+) diff --git a/selftest/knownfail.d/multilock b/selftest/knownfail.d/multilock index 01538acc5a8..b3fe93fd34e 100644 --- a/selftest/knownfail.d/multilock +++ b/selftest/knownfail.d/multilock @@ -1,2 +1,3 @@ ^samba3.raw.lock.multilock3.*nt4_dc ^samba3.raw.lock.multilock4.*nt4_dc +^samba3.raw.lock.multilock5.*nt4_dc diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c index 26339f9b28b..c29a577b34a 100644 --- a/source4/torture/raw/lock.c +++ b/source4/torture/raw/lock.c @@ -3025,6 +3025,274 @@ done: return ret; } +/* + test multi5 Locking&X operation + This test is designed to show that + lock precedence on the server is based + on the order received, not on the ability + to grant. + + Compared to test_multilock3() (above) + this test demonstrates that the initial + lock request that block the following + exclusive locks can be a shared lock. + + For example: + + All locks except (a) are LOCKING_ANDX_EXCLUSIVE_LOCK (rw). + + (a) lock(ro) 100->109, 120->129 (granted) + (b) lock 100->109, 120->129 (blocks, timeout=20s) + (c) lock 100->109 (blocks, timeout=2s) + (d) lock 110->119 (granted) + (e) lock 110->119 (blocks, timeout=20s) + (f) unlock 100->109 (a) + (g) lock 100->109 (not granted, blocked by (b)) + (h) lock 100->109 (not granted, blocked by itself (b)) + (i) lock (c) will not be granted(conflict, times out) + as lock (b) will take precedence. + (j) unlock 110-119 (d) + (k) lock (e) completes and is not blocked by (a) nor (b) + (l) lock 100->109 (not granted(conflict), blocked by (b)) + (m) lock 100->109 (not granted(conflict), blocked by itself (b)) + (n) unlock 120-129 (a) + (o) lock (b) completes +*/ +static bool test_multilock5(struct torture_context *tctx, + struct smbcli_state *cli) +{ + union smb_lock io; + struct smb_lock_entry lock[2]; + union smb_lock io3; + struct smb_lock_entry lock3[1]; + NTSTATUS status; + bool ret = true; + int fnum; + const char *fname = BASEDIR "\\multilock5_test.txt"; + time_t t; + struct smbcli_request *req = NULL; + struct smbcli_request *req2 = NULL; + struct smbcli_request *req4 = NULL; + + torture_assert(tctx, torture_setup_dir(cli, BASEDIR), + "Failed to setup up test directory: " BASEDIR); + + torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 5\n"); + io.generic.level = RAW_LOCK_LOCKX; + + /* Create the test file. */ + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, + "Failed to create %s - %s\n", + fname, smbcli_errstr(cli->tree))); + + /* + * a) + * Lock regions 100->109, 120->129 as + * two separate write locks in one request. + * (read only) + */ + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 2; + io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + lock[1].pid = cli->session->pid; + lock[1].offset = 120; + lock[1].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * b) + * Now request the same locks on a different + * context as blocking locks. + * (read write) + */ + io.lockx.in.timeout = 20000; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock[0].pid = cli->session->pid+1; + lock[1].pid = cli->session->pid+1; + req = smb_raw_lock_send(cli->tree, &io); + torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * c) + * Request the first lock again on a separate context. + * Wait 2 seconds. This should time out (the previous + * multi-lock request should take precedence). + * (read write) + */ + io.lockx.in.timeout = 2000; + lock[0].pid = cli->session->pid+2; + io.lockx.in.lock_cnt = 1; + req2 = smb_raw_lock_send(cli->tree, &io); + torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * d) + * Lock regions 110->119 + */ + io3.lockx.level = RAW_LOCK_LOCKX; + io3.lockx.in.file.fnum = fnum; + io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io3.lockx.in.timeout = 0; + io3.lockx.in.ulock_cnt = 0; + io3.lockx.in.lock_cnt = 1; + io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock3[0].pid = cli->session->pid+3; + lock3[0].offset = 110; + lock3[0].count = 10; + io3.lockx.in.locks = &lock3[0]; + status = smb_raw_lock(cli->tree, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * e) + * try 110-119 again + */ + io3.lockx.in.timeout = 20000; + lock3[0].pid = cli->session->pid+4; + req4 = smb_raw_lock_send(cli->tree, &io3); + torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * f) + * Unlock (a) lock[0] 100-109 + * + * Note we send LOCKING_ANDX_EXCLUSIVE_LOCK + * while the lock used LOCKING_ANDX_SHARED_LOCK + * to check if that also works. + */ + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lock[0]; + lock[0].pid = cli->session->pid; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * g) + * try to lock lock[0] 100-109 again + */ + lock[0].pid = cli->session->pid+5; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + /* + * h) + * try to lock lock[0] 100-109 again with the pid (b) + * that's still waiting. + * (read write) + */ + lock[0].pid = cli->session->pid+1; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV, + "req2 should still wait"); + + /* + * i) + * Did the second lock complete (should time out) ? + */ + status = smbcli_request_simple_recv(req2); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV, + "req4 should still wait"); + + /* + * j) + * Unlock (d) lock[0] 110-119 + */ + io3.lockx.in.timeout = 0; + io3.lockx.in.ulock_cnt = 1; + io3.lockx.in.lock_cnt = 0; + lock3[0].pid = cli->session->pid+3; + status = smb_raw_lock(cli->tree, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * k) + * receive the successful blocked lock requests + * on 110-119 while the 100-109/120-129 is still waiting. + */ + status = smbcli_request_simple_recv(req4); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * l) + * try to lock lock[0] 100-109 again + */ + lock[0].pid = cli->session->pid+6; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* + * m) + * try to lock lock[0] 100-109 again with the pid (b) + * that's still waiting + */ + lock[0].pid = cli->session->pid+1; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + + /* Start the clock. */ + t = time_mono(NULL); + + /* + * n) + * Unlock (a) lock[1] 120-129 + */ + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lock[1]; + lock[1].pid = cli->session->pid; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * o) + * receive the successful blocked lock request (b) + */ + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Fail if this took more than 2 seconds. */ + torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx, + "Blocking locks were not granted immediately (%s)\n", + __location__)); +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + /* basic testing of lock calls */ @@ -3049,6 +3317,7 @@ struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx) torture_suite_add_1smb_test(suite, "multilock2", test_multilock2); torture_suite_add_1smb_test(suite, "multilock3", test_multilock3); torture_suite_add_1smb_test(suite, "multilock4", test_multilock4); + torture_suite_add_1smb_test(suite, "multilock5", test_multilock5); return suite; } -- 2.17.1 From d857b21d4fec18aa71f9bec4343924053dd9f083 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 16 Aug 2019 16:24:34 +0200 Subject: [PATCH 166/376] s4:torture/raw: add multilock6 test This is similar to multilock3, but uses a read-only (LOCKING_ANDX_SHARED_LOCK) locks for the 2nd lock request. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit d3bc0199697fd7d6e04479321ca644a227bc4ede) --- selftest/knownfail | 1 + selftest/knownfail.d/multilock | 1 + source4/torture/raw/lock.c | 263 +++++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index ded80b12259..7b54b77a708 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -109,6 +109,7 @@ .*net.api.delshare.* # DelShare isn't implemented yet ^samba4.smb2.oplock.doc ^samba4.smb2.lock.valid-request +^samba4.raw.lock.multilock6.ad_dc_ntvfs ^samba4.ldap.python \(ad_dc_default\).Test add_ldif\(\) with BASE64 security descriptor input using WRONG domain SID\(.*\)$ ^samba4.raw.lock.*.async # bug 6960 ^samba4.raw.open.ntcreatex_supersede diff --git a/selftest/knownfail.d/multilock b/selftest/knownfail.d/multilock index b3fe93fd34e..9fa497bd643 100644 --- a/selftest/knownfail.d/multilock +++ b/selftest/knownfail.d/multilock @@ -1,3 +1,4 @@ ^samba3.raw.lock.multilock3.*nt4_dc ^samba3.raw.lock.multilock4.*nt4_dc ^samba3.raw.lock.multilock5.*nt4_dc +^samba3.raw.lock.multilock6.*nt4_dc diff --git a/source4/torture/raw/lock.c b/source4/torture/raw/lock.c index c29a577b34a..f684e923a49 100644 --- a/source4/torture/raw/lock.c +++ b/source4/torture/raw/lock.c @@ -3293,6 +3293,268 @@ done: return ret; } +/* + test multi6 Locking&X operation + This test is designed to show that + lock precedence on the server is based + on the order received, not on the ability + to grant. + + Compared to test_multilock4() (above) + this test demonstrates the behavior if + only just the first blocking lock + being a shared lock. + + For example: + + All locks except (b) are LOCKING_ANDX_EXCLUSIVE_LOCK (rw). + + (a) lock 100->109, 120->129 (granted) + (b) lock(ro) 100->109, 120->129 (blocks, timeout=20s) + (c) lock 100->109 (blocks, timeout=2s) + (d) lock 110->119 (granted) + (e) lock 110->119 (blocks, timeout=20s) + (f) unlock 100->109 (a) + (g) lock 100->109 (not granted, blocked by (b)) + (h) lock 100->109 (not granted, blocked by itself (b)) + (i) lock (c) will not be granted(conflict, times out) + as lock (b) will take precedence. + (j) unlock 110-119 (d) + (k) lock (e) completes and is not blocked by (a) nor (b) + (l) lock 100->109 (not granted(conflict), blocked by (b)) + (m) lock 100->109 (not granted(conflict), blocked by itself (b)) + (n) unlock 120-129 (a) + (o) lock (b) completes +*/ +static bool test_multilock6(struct torture_context *tctx, + struct smbcli_state *cli) +{ + union smb_lock io; + struct smb_lock_entry lock[2]; + union smb_lock io3; + struct smb_lock_entry lock3[1]; + NTSTATUS status; + bool ret = true; + int fnum; + const char *fname = BASEDIR "\\multilock6_test.txt"; + time_t t; + struct smbcli_request *req = NULL; + struct smbcli_request *req2 = NULL; + struct smbcli_request *req4 = NULL; + + torture_assert(tctx, torture_setup_dir(cli, BASEDIR), + "Failed to setup up test directory: " BASEDIR); + + torture_comment(tctx, "Testing LOCKING_ANDX multi-lock 6\n"); + io.generic.level = RAW_LOCK_LOCKX; + + /* Create the test file. */ + fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE); + torture_assert(tctx,(fnum != -1), talloc_asprintf(tctx, + "Failed to create %s - %s\n", + fname, smbcli_errstr(cli->tree))); + + /* + * a) + * Lock regions 100->109, 120->129 as + * two separate write locks in one request. + */ + io.lockx.level = RAW_LOCK_LOCKX; + io.lockx.in.file.fnum = fnum; + io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 2; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock[0].pid = cli->session->pid; + lock[0].offset = 100; + lock[0].count = 10; + lock[1].pid = cli->session->pid; + lock[1].offset = 120; + lock[1].count = 10; + io.lockx.in.locks = &lock[0]; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * b) + * Now request the same locks on a different + * context as blocking locks. + * (read only) + */ + io.lockx.in.timeout = 20000; + io.lockx.in.mode = LOCKING_ANDX_SHARED_LOCK; + lock[0].pid = cli->session->pid+1; + lock[1].pid = cli->session->pid+1; + req = smb_raw_lock_send(cli->tree, &io); + torture_assert(tctx,(req != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * c) + * Request the first lock again on a separate context. + * Wait 2 seconds. This should time out (the previous + * multi-lock request should take precedence). + */ + io.lockx.in.timeout = 2000; + io.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock[0].pid = cli->session->pid+2; + io.lockx.in.lock_cnt = 1; + req2 = smb_raw_lock_send(cli->tree, &io); + torture_assert(tctx,(req2 != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * d) + * Lock regions 110->119 + */ + io3.lockx.level = RAW_LOCK_LOCKX; + io3.lockx.in.file.fnum = fnum; + io3.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + io3.lockx.in.timeout = 0; + io3.lockx.in.ulock_cnt = 0; + io3.lockx.in.lock_cnt = 1; + io3.lockx.in.mode = LOCKING_ANDX_EXCLUSIVE_LOCK; + lock3[0].pid = cli->session->pid+3; + lock3[0].offset = 110; + lock3[0].count = 10; + io3.lockx.in.locks = &lock3[0]; + status = smb_raw_lock(cli->tree, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * e) + * try 110-119 again + */ + io3.lockx.in.timeout = 20000; + lock3[0].pid = cli->session->pid+4; + req4 = smb_raw_lock_send(cli->tree, &io3); + torture_assert(tctx,(req4 != NULL), talloc_asprintf(tctx, + "Failed to setup timed locks (%s)\n", __location__)); + + /* + * f) + * Unlock (a) lock[0] 100-109 + */ + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lock[0]; + lock[0].pid = cli->session->pid; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * g) + * try to lock lock[0] 100-109 again + */ + lock[0].pid = cli->session->pid+5; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED); + + /* + * h) + * try to lock lock[0] 100-109 again with the pid (b) + * that's still waiting + */ + lock[0].pid = cli->session->pid+1; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req2->state <= SMBCLI_REQUEST_RECV, + "req2 should still wait"); + + /* + * i) + * Did the second lock (c) complete (should time out) ? + */ + status = smbcli_request_simple_recv(req2); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + torture_assert(tctx, req4->state <= SMBCLI_REQUEST_RECV, + "req4 should still wait"); + + /* + * j) + * Unlock (d) lock[0] 110-119 + */ + io3.lockx.in.timeout = 0; + io3.lockx.in.ulock_cnt = 1; + io3.lockx.in.lock_cnt = 0; + lock3[0].pid = cli->session->pid+3; + status = smb_raw_lock(cli->tree, &io3); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * k) + * receive the successful blocked lock request (e) + * on 110-119 while (b) 100-109/120-129 is still waiting. + */ + status = smbcli_request_simple_recv(req4); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * l) + * try to lock lock[0] 100-109 again + */ + lock[0].pid = cli->session->pid+6; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + /* + * m) + * try to lock lock[0] 100-109 again with the pid (b) + * that's still waiting + */ + lock[0].pid = cli->session->pid+1; + io.lockx.in.ulock_cnt = 0; + io.lockx.in.lock_cnt = 1; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT); + + torture_assert(tctx, req->state <= SMBCLI_REQUEST_RECV, + "req should still wait"); + + /* Start the clock. */ + t = time_mono(NULL); + + /* + * n) + * Unlock (a) lock[1] 120-129 + */ + io.lockx.in.timeout = 0; + io.lockx.in.ulock_cnt = 1; + io.lockx.in.lock_cnt = 0; + io.lockx.in.locks = &lock[1]; + lock[1].pid = cli->session->pid; + status = smb_raw_lock(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + /* + * o) + * receive the successful blocked lock request (b) + */ + status = smbcli_request_simple_recv(req); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Fail if this took more than 2 seconds. */ + torture_assert(tctx,!(time_mono(NULL) > t+2), talloc_asprintf(tctx, + "Blocking locks were not granted immediately (%s)\n", + __location__)); +done: + smb_raw_exit(cli->session); + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + /* basic testing of lock calls */ @@ -3318,6 +3580,7 @@ struct torture_suite *torture_raw_lock(TALLOC_CTX *mem_ctx) torture_suite_add_1smb_test(suite, "multilock3", test_multilock3); torture_suite_add_1smb_test(suite, "multilock4", test_multilock4); torture_suite_add_1smb_test(suite, "multilock5", test_multilock5); + torture_suite_add_1smb_test(suite, "multilock6", test_multilock6); return suite; } -- 2.17.1 From 9f46f3b0e722d993a650fc3659e842aad08837a6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 18:17:47 +0200 Subject: [PATCH 167/376] s3:blocking: use timeval_expired(&state->endtime) to stop processing This is less racy than timeval_elapsed() > 0 as the current time is already expired and timeout = 0 will always work correct. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 5a841a43f9c4f862e2d7235429363b3066cf5850) --- source3/smbd/blocking.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index a87d62d910a..9f64a86d3ee 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -159,9 +159,10 @@ struct tevent_req *smbd_smb1_do_locks_send( struct share_mode_lock *lck = NULL; struct server_id blocking_pid = { 0 }; uint64_t blocking_smblctx = 0; - struct timeval endtime; + struct timeval endtime = { 0 }; NTSTATUS status = NT_STATUS_OK; bool ok; + bool expired; req = tevent_req_create( mem_ctx, &state, struct smbd_smb1_do_locks_state); @@ -251,19 +252,28 @@ struct tevent_req *smbd_smb1_do_locks_send( state->timeout = lp_lock_spin_time(); } } + state->endtime = timeval_current_ofs_msec(state->timeout); DBG_DEBUG("timeout=%"PRIu32", blocking_smblctx=%"PRIu64"\n", state->timeout, blocking_smblctx); /* + * The client specified timeout expired + * avoid further retries. + * + * Otherwise keep waiting either waiting + * for changes in locking.tdb or the polling + * mode timers waiting for posix locks. + * * If the endtime is not elapsed yet, * it means we'll retry after a timeout. * In that case we'll have to return * NT_STATUS_FILE_LOCK_CONFLICT * instead of NT_STATUS_LOCK_NOT_GRANTED. */ - if (state->timeout == 0) { + expired = timeval_expired(&state->endtime); + if (expired) { status = state->deny_status; tevent_req_nterror(req, status); goto done; @@ -278,7 +288,6 @@ struct tevent_req *smbd_smb1_do_locks_send( TALLOC_FREE(lck); tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req); - state->endtime = timeval_current_ofs_msec(state->timeout); endtime = state->endtime; if (blocking_smblctx == UINT64_MAX) { @@ -363,13 +372,13 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) struct smbd_smb1_do_locks_state *retry_state = tevent_req_data( retry_req, struct smbd_smb1_do_locks_state); struct share_mode_lock *lck; - struct timeval endtime; + struct timeval endtime = { 0 }; struct server_id blocking_pid = { 0 }; uint64_t blocking_smblctx = 0; struct tevent_req *subreq = NULL; NTSTATUS status; bool ok; - double elapsed; + bool expired; lck = get_existing_share_mode_lock(state, fsp->file_id); if (tevent_req_nomem(lck, req)) { @@ -393,7 +402,7 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) } /* - * The client specified timeout elapsed + * The client specified timeout expired * avoid further retries. * * Otherwise keep waiting either waiting @@ -406,8 +415,8 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) * NT_STATUS_FILE_LOCK_CONFLICT * instead of NT_STATUS_LOCK_NOT_GRANTED. */ - elapsed = timeval_elapsed(&state->endtime); - if (elapsed > 0) { + expired = timeval_expired(&state->endtime); + if (expired) { status = state->deny_status; goto done; } -- 2.17.1 From f479c7bc03a06a409b0037d7957806ba3208b55b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 18:02:57 +0200 Subject: [PATCH 168/376] s3:blocking: split out smbd_smb1_do_locks_setup_timeout() This function can be called multiple times, but only the first time will setup the endtime. And the endtime is relative to the request time and not the current time. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 8da7c10a58292022ee57406db9a365de9ffaf5cf) --- source3/smbd/blocking.c | 98 ++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 9f64a86d3ee..98074c0c09a 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -117,6 +117,68 @@ static void smbd_smb1_do_locks_retry(struct tevent_req *subreq); static void smbd_smb1_blocked_locks_cleanup( struct tevent_req *req, enum tevent_req_state req_state); +static void smbd_smb1_do_locks_setup_timeout( + struct smbd_smb1_do_locks_state *state, + const struct smbd_lock_element *blocker) +{ + struct files_struct *fsp = state->fsp; + + if (!timeval_is_zero(&state->endtime)) { + /* + * already done + */ + return; + } + + if ((state->timeout != 0) && (state->timeout != UINT32_MAX)) { + /* + * Windows internal resolution for blocking locks + * seems to be about 200ms... Don't wait for less than + * that. JRA. + */ + state->timeout = MAX(state->timeout, lp_lock_spin_time()); + } + + if (state->timeout != 0) { + goto set_endtime; + } + + if (blocker == NULL) { + goto set_endtime; + } + + if ((blocker->offset >= 0xEF000000) && + ((blocker->offset >> 63) == 0)) { + /* + * This must be an optimization of an ancient + * application bug... + */ + state->timeout = lp_lock_spin_time(); + } + + if ((fsp->lock_failure_seen) && + (blocker->offset == fsp->lock_failure_offset)) { + /* + * Delay repeated lock attempts on the same + * lock. Maybe a more advanced version of the + * above check? + */ + DBG_DEBUG("Delaying lock request due to previous " + "failure\n"); + state->timeout = lp_lock_spin_time(); + } + +set_endtime: + /* + * Note state->timeout might still 0, + * but that's ok, as we don't want to retry + * in that case. + */ + state->endtime = timeval_add(&state->smbreq->request_time, + state->timeout / 1000, + (state->timeout % 1000) * 1000); +} + static void smbd_smb1_do_locks_update_polling_msecs( struct smbd_smb1_do_locks_state *state) { @@ -196,15 +258,6 @@ struct tevent_req *smbd_smb1_do_locks_send( return tevent_req_post(req, ev); } - if ((state->timeout != 0) && (state->timeout != UINT32_MAX)) { - /* - * Windows internal resolution for blocking locks - * seems to be about 200ms... Don't wait for less than - * that. JRA. - */ - state->timeout = MAX(state->timeout, lp_lock_spin_time()); - } - lck = get_existing_share_mode_lock(state, state->fsp->file_id); if (tevent_req_nomem(lck, req)) { DBG_DEBUG("Could not get share mode lock\n"); @@ -228,32 +281,7 @@ struct tevent_req *smbd_smb1_do_locks_send( goto done; } - if (state->timeout == 0) { - struct smbd_lock_element *blocker = &locks[state->blocker]; - - if ((blocker->offset >= 0xEF000000) && - ((blocker->offset >> 63) == 0)) { - /* - * This must be an optimization of an ancient - * application bug... - */ - state->timeout = lp_lock_spin_time(); - } - - if ((fsp->lock_failure_seen) && - (blocker->offset == fsp->lock_failure_offset)) { - /* - * Delay repeated lock attempts on the same - * lock. Maybe a more advanced version of the - * above check? - */ - DBG_DEBUG("Delaying lock request due to previous " - "failure\n"); - state->timeout = lp_lock_spin_time(); - } - } - state->endtime = timeval_current_ofs_msec(state->timeout); - + smbd_smb1_do_locks_setup_timeout(state, &locks[state->blocker]); DBG_DEBUG("timeout=%"PRIu32", blocking_smblctx=%"PRIu64"\n", state->timeout, blocking_smblctx); -- 2.17.1 From 333026209a8abe5d9d00297ce7f0d6cdf66d6ce0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 19 Aug 2019 15:21:50 +0200 Subject: [PATCH 169/376] s3:blocking: do the timeout calculation before calling dbwrap_watched_watch_send() This makes the next commits easier to understand. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 997548a5f1a14d82f1e80cce6d9ee55e85b5107c) --- source3/smbd/blocking.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 98074c0c09a..ac90f8c3ef1 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -308,14 +308,6 @@ struct tevent_req *smbd_smb1_do_locks_send( } state->deny_status = NT_STATUS_FILE_LOCK_CONFLICT; - subreq = dbwrap_watched_watch_send( - state, state->ev, lck->data->record, blocking_pid); - if (tevent_req_nomem(subreq, req)) { - goto done; - } - TALLOC_FREE(lck); - tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req); - endtime = state->endtime; if (blocking_smblctx == UINT64_MAX) { @@ -330,6 +322,14 @@ struct tevent_req *smbd_smb1_do_locks_send( endtime = timeval_min(&endtime, &tmp); } + subreq = dbwrap_watched_watch_send( + state, state->ev, lck->data->record, blocking_pid); + if (tevent_req_nomem(subreq, req)) { + goto done; + } + TALLOC_FREE(lck); + tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req); + ok = tevent_req_set_endtime(subreq, state->ev, endtime); if (!ok) { tevent_req_oom(req); @@ -450,14 +450,6 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) } state->deny_status = NT_STATUS_FILE_LOCK_CONFLICT; - subreq = dbwrap_watched_watch_send( - state, state->ev, lck->data->record, blocking_pid); - if (tevent_req_nomem(subreq, req)) { - goto done; - } - TALLOC_FREE(lck); - tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req); - endtime = state->endtime; if (blocking_smblctx == UINT64_MAX) { @@ -472,6 +464,14 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) endtime = timeval_min(&endtime, &tmp); } + subreq = dbwrap_watched_watch_send( + state, state->ev, lck->data->record, blocking_pid); + if (tevent_req_nomem(subreq, req)) { + goto done; + } + TALLOC_FREE(lck); + tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req); + ok = tevent_req_set_endtime(subreq, state->ev, endtime); if (!ok) { status = NT_STATUS_NO_MEMORY; -- 2.17.1 From 11e489b0789d7c9cc7f082c054c97c6c4c6f131a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 16 Aug 2019 14:55:13 +0200 Subject: [PATCH 170/376] s3:blocking: fix the fsp->blocked_smb1_lock_reqs handling A new request is first checks against all pending requests before checking the already granted locks. Before we retried the lock array of another request (the first in the list), but then finished current request, which is wrong. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 312327106271abafeb53e62dfb71a38bf93e2d41) --- selftest/knownfail.d/multilock | 4 - source3/smbd/blocking.c | 134 ++++++++++++++++++++++++++++++--- 2 files changed, 125 insertions(+), 13 deletions(-) delete mode 100644 selftest/knownfail.d/multilock diff --git a/selftest/knownfail.d/multilock b/selftest/knownfail.d/multilock deleted file mode 100644 index 9fa497bd643..00000000000 --- a/selftest/knownfail.d/multilock +++ /dev/null @@ -1,4 +0,0 @@ -^samba3.raw.lock.multilock3.*nt4_dc -^samba3.raw.lock.multilock4.*nt4_dc -^samba3.raw.lock.multilock5.*nt4_dc -^samba3.raw.lock.multilock6.*nt4_dc diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index ac90f8c3ef1..39042d2f46d 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -116,6 +116,14 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req); static void smbd_smb1_do_locks_retry(struct tevent_req *subreq); static void smbd_smb1_blocked_locks_cleanup( struct tevent_req *req, enum tevent_req_state req_state); +static NTSTATUS smbd_smb1_do_locks_check( + struct files_struct *fsp, + enum brl_flavour lock_flav, + uint16_t num_locks, + struct smbd_lock_element *locks, + uint16_t *blocker_idx, + struct server_id *blocking_pid, + uint64_t *blocking_smblctx); static void smbd_smb1_do_locks_setup_timeout( struct smbd_smb1_do_locks_state *state, @@ -264,7 +272,7 @@ struct tevent_req *smbd_smb1_do_locks_send( return tevent_req_post(req, ev); } - status = smbd_do_locks_try( + status = smbd_smb1_do_locks_check( state->fsp, state->lock_flav, state->num_locks, @@ -390,15 +398,123 @@ static void smbd_smb1_blocked_locks_cleanup( fsp, blocked, struct tevent_req *, num_blocked-1); } +static NTSTATUS smbd_smb1_do_locks_check_blocked( + uint16_t num_blocked, + struct smbd_lock_element *blocked, + uint16_t num_locks, + struct smbd_lock_element *locks, + uint16_t *blocker_idx, + uint64_t *blocking_smblctx) +{ + uint16_t li; + + for (li=0; li < num_locks; li++) { + struct smbd_lock_element *l = &locks[li]; + uint16_t bi; + bool valid; + + valid = byte_range_valid(l->offset, l->count); + if (!valid) { + return NT_STATUS_INVALID_LOCK_RANGE; + } + + for (bi = 0; bi < num_blocked; bi++) { + struct smbd_lock_element *b = &blocked[li]; + bool overlap; + + /* Read locks never conflict. */ + if (l->brltype == READ_LOCK && b->brltype == READ_LOCK) { + continue; + } + + overlap = byte_range_overlap(l->offset, + l->count, + b->offset, + b->count); + if (!overlap) { + continue; + } + + *blocker_idx = li; + *blocking_smblctx = b->smblctx; + return NT_STATUS_LOCK_NOT_GRANTED; + } + } + + return NT_STATUS_OK; +} + +static NTSTATUS smbd_smb1_do_locks_check( + struct files_struct *fsp, + enum brl_flavour lock_flav, + uint16_t num_locks, + struct smbd_lock_element *locks, + uint16_t *blocker_idx, + struct server_id *blocking_pid, + uint64_t *blocking_smblctx) +{ + struct tevent_req **blocked = fsp->blocked_smb1_lock_reqs; + size_t num_blocked = talloc_array_length(blocked); + NTSTATUS status; + size_t bi; + + /* + * We check the pending/blocked requests + * from the oldest to the youngest request. + * + * Note due to the retry logic the current request + * might already be in the list. + */ + + for (bi = 0; bi < num_blocked; bi++) { + struct smbd_smb1_do_locks_state *blocked_state = + tevent_req_data(blocked[bi], + struct smbd_smb1_do_locks_state); + + if (blocked_state->locks == locks) { + SMB_ASSERT(blocked_state->num_locks == num_locks); + SMB_ASSERT(blocked_state->lock_flav == lock_flav); + + /* + * We found ourself... + */ + break; + } + + status = smbd_smb1_do_locks_check_blocked( + blocked_state->num_locks, + blocked_state->locks, + num_locks, + locks, + blocker_idx, + blocking_smblctx); + if (!NT_STATUS_IS_OK(status)) { + *blocking_pid = messaging_server_id( + fsp->conn->sconn->msg_ctx); + return status; + } + } + + status = smbd_do_locks_try( + fsp, + lock_flav, + num_locks, + locks, + blocker_idx, + blocking_pid, + blocking_smblctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + static void smbd_smb1_do_locks_try(struct tevent_req *req) { struct smbd_smb1_do_locks_state *state = tevent_req_data( req, struct smbd_smb1_do_locks_state); struct files_struct *fsp = state->fsp; - struct tevent_req **blocked = fsp->blocked_smb1_lock_reqs; - struct tevent_req *retry_req = blocked[0]; - struct smbd_smb1_do_locks_state *retry_state = tevent_req_data( - retry_req, struct smbd_smb1_do_locks_state); struct share_mode_lock *lck; struct timeval endtime = { 0 }; struct server_id blocking_pid = { 0 }; @@ -414,11 +530,11 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) return; } - status = smbd_do_locks_try( + status = smbd_smb1_do_locks_check( fsp, - retry_state->lock_flav, - retry_state->num_locks, - retry_state->locks, + state->lock_flav, + state->num_locks, + state->locks, &state->blocker, &blocking_pid, &blocking_smblctx); -- 2.17.1 From 5e9d294a045d7b7e1d77dd5f306d74b165585344 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 18:18:50 +0200 Subject: [PATCH 171/376] s3:blocking: call smbd_smb1_do_locks_setup_timeout() also in smbd_smb1_do_locks_try() This is a noop if smbd_smb1_do_locks_setup_timeout() was called before. But it allows us to use smbd_smb1_do_locks_try() in smbd_smb1_do_locks_send() in a following commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 6e30a89b3f00ad55391454fbaa1272074e1962f0) --- source3/smbd/blocking.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 39042d2f46d..77dfc5a3d44 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -545,6 +545,11 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) goto done; } + smbd_smb1_do_locks_setup_timeout(state, &state->locks[state->blocker]); + DBG_DEBUG("timeout=%"PRIu32", blocking_smblctx=%"PRIu64"\n", + state->timeout, + blocking_smblctx); + /* * The client specified timeout expired * avoid further retries. -- 2.17.1 From c8086b8873b37fde75dfbcd0054b5db7565b8708 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Aug 2019 20:09:55 +0200 Subject: [PATCH 172/376] s3:blocking: make use of smbd_smb1_do_locks_try() in smbd_smb1_do_locks_send() We only need the logic to call smbd_smb1_do_locks_check() and a possible retry once in smbd_smb1_do_locks_try(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 8975673e3c3f9f7dbdb7ba7562bb81a62cd24e2e) --- source3/smbd/blocking.c | 90 ++--------------------------------------- 1 file changed, 4 insertions(+), 86 deletions(-) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 77dfc5a3d44..514985bcd75 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -224,15 +224,9 @@ struct tevent_req *smbd_smb1_do_locks_send( uint16_t num_locks, struct smbd_lock_element *locks) { - struct tevent_req *req = NULL, *subreq = NULL; + struct tevent_req *req = NULL; struct smbd_smb1_do_locks_state *state = NULL; - struct share_mode_lock *lck = NULL; - struct server_id blocking_pid = { 0 }; - uint64_t blocking_smblctx = 0; - struct timeval endtime = { 0 }; - NTSTATUS status = NT_STATUS_OK; bool ok; - bool expired; req = tevent_req_create( mem_ctx, &state, struct smbd_smb1_do_locks_state); @@ -266,94 +260,18 @@ struct tevent_req *smbd_smb1_do_locks_send( return tevent_req_post(req, ev); } - lck = get_existing_share_mode_lock(state, state->fsp->file_id); - if (tevent_req_nomem(lck, req)) { - DBG_DEBUG("Could not get share mode lock\n"); + smbd_smb1_do_locks_try(req); + if (!tevent_req_is_in_progress(req)) { return tevent_req_post(req, ev); } - status = smbd_smb1_do_locks_check( - state->fsp, - state->lock_flav, - state->num_locks, - state->locks, - &state->blocker, - &blocking_pid, - &blocking_smblctx); - if (NT_STATUS_IS_OK(status)) { - tevent_req_done(req); - goto done; - } - if (!ERROR_WAS_LOCK_DENIED(status)) { - tevent_req_nterror(req, status); - goto done; - } - - smbd_smb1_do_locks_setup_timeout(state, &locks[state->blocker]); - DBG_DEBUG("timeout=%"PRIu32", blocking_smblctx=%"PRIu64"\n", - state->timeout, - blocking_smblctx); - - /* - * The client specified timeout expired - * avoid further retries. - * - * Otherwise keep waiting either waiting - * for changes in locking.tdb or the polling - * mode timers waiting for posix locks. - * - * If the endtime is not elapsed yet, - * it means we'll retry after a timeout. - * In that case we'll have to return - * NT_STATUS_FILE_LOCK_CONFLICT - * instead of NT_STATUS_LOCK_NOT_GRANTED. - */ - expired = timeval_expired(&state->endtime); - if (expired) { - status = state->deny_status; - tevent_req_nterror(req, status); - goto done; - } - state->deny_status = NT_STATUS_FILE_LOCK_CONFLICT; - - endtime = state->endtime; - - if (blocking_smblctx == UINT64_MAX) { - struct timeval tmp; - - smbd_smb1_do_locks_update_polling_msecs(state); - - DBG_DEBUG("Blocked on a posix lock. Retry in %"PRIu32" msecs\n", - state->polling_msecs); - - tmp = timeval_current_ofs_msec(state->polling_msecs); - endtime = timeval_min(&endtime, &tmp); - } - - subreq = dbwrap_watched_watch_send( - state, state->ev, lck->data->record, blocking_pid); - if (tevent_req_nomem(subreq, req)) { - goto done; - } - TALLOC_FREE(lck); - tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req); - - ok = tevent_req_set_endtime(subreq, state->ev, endtime); - if (!ok) { - tevent_req_oom(req); - goto done; - } - ok = smbd_smb1_fsp_add_blocked_lock_req(fsp, req); if (!ok) { tevent_req_oom(req); - goto done; + return tevent_req_post(req, ev); } tevent_req_set_cleanup_fn(req, smbd_smb1_blocked_locks_cleanup); return req; -done: - TALLOC_FREE(lck); - return tevent_req_post(req, ev); } static void smbd_smb1_blocked_locks_cleanup( -- 2.17.1 From a1117587afb6bf2f813982dfca4a47e982f44b96 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 19 Aug 2019 15:29:32 +0200 Subject: [PATCH 173/376] s3:blocking: handle NT_STATUS_RETRY from the VFS backend This allows the VFS backends to implement async byte range locking. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 7d1cd6f22e7e3d95aba04c45776057945c2a5e30) --- source3/smbd/blocking.c | 84 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 514985bcd75..fbd1ea812f3 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -103,6 +103,7 @@ struct smbd_smb1_do_locks_state { struct files_struct *fsp; uint32_t timeout; uint32_t polling_msecs; + uint32_t retry_msecs; struct timeval endtime; bool large_offset; /* required for correct cancel */ enum brl_flavour lock_flav; @@ -187,6 +188,33 @@ set_endtime: (state->timeout % 1000) * 1000); } +static void smbd_smb1_do_locks_update_retry_msecs( + struct smbd_smb1_do_locks_state *state) +{ + /* + * The default lp_lock_spin_time() is 200ms, + * we just use half of it to trigger the first retry. + * + * v_min is in the range of 0.001 to 10 secs + * (0.1 secs by default) + * + * v_max is in the range of 0.01 to 100 secs + * (1.0 secs by default) + * + * The typical steps are: + * 0.1, 0.2, 0.3, 0.4, ... 1.0 + */ + uint32_t v_min = MAX(2, MIN(20000, lp_lock_spin_time()))/2; + uint32_t v_max = 10 * v_min; + + if (state->retry_msecs >= v_max) { + state->retry_msecs = v_max; + return; + } + + state->retry_msecs += v_min; +} + static void smbd_smb1_do_locks_update_polling_msecs( struct smbd_smb1_do_locks_state *state) { @@ -459,9 +487,60 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) if (NT_STATUS_IS_OK(status)) { goto done; } + if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { + /* + * We got NT_STATUS_RETRY, + * we reset polling_msecs so that + * that the retries based on LOCK_NOT_GRANTED + * will later start with small intervalls again. + */ + state->polling_msecs = 0; + + /* + * The backend wasn't able to decide yet. + * We need to wait even for non-blocking + * locks. + * + * The backend uses blocking_smblctx == UINT64_MAX + * to indicate that we should use retry timers. + * + * It uses blocking_smblctx == 0 to indicate + * it will use share_mode_wakeup_waiters() + * to wake us. Note that unrelated changes in + * locking.tdb may cause retries. + */ + + if (blocking_smblctx != UINT64_MAX) { + SMB_ASSERT(blocking_smblctx == 0); + goto setup_retry; + } + + smbd_smb1_do_locks_update_retry_msecs(state); + + DBG_DEBUG("Waiting for a backend decision. " + "Retry in %"PRIu32" msecs\n", + state->retry_msecs); + + /* + * We completely ignore state->endtime here + * we we'll wait for a backend decision forever. + * If the backend is smart enough to implement + * some NT_STATUS_RETRY logic, it has to + * switch to any other status after in order + * to avoid waiting forever. + */ + endtime = timeval_current_ofs_msec(state->retry_msecs); + goto setup_retry; + } if (!ERROR_WAS_LOCK_DENIED(status)) { goto done; } + /* + * We got LOCK_NOT_GRANTED, make sure + * a following STATUS_RETRY will start + * with short intervalls again. + */ + state->retry_msecs = 0; smbd_smb1_do_locks_setup_timeout(state, &state->locks[state->blocker]); DBG_DEBUG("timeout=%"PRIu32", blocking_smblctx=%"PRIu64"\n", @@ -503,6 +582,7 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) endtime = timeval_min(&endtime, &tmp); } +setup_retry: subreq = dbwrap_watched_watch_send( state, state->ev, lck->data->record, blocking_pid); if (tevent_req_nomem(subreq, req)) { @@ -511,6 +591,10 @@ static void smbd_smb1_do_locks_try(struct tevent_req *req) TALLOC_FREE(lck); tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req); + if (timeval_is_zero(&endtime)) { + return; + } + ok = tevent_req_set_endtime(subreq, state->ev, endtime); if (!ok) { status = NT_STATUS_NO_MEMORY; -- 2.17.1 From 74527a20584bd9d22c8487a6ebdeaca21525afe3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 19 Aug 2019 16:25:59 +0200 Subject: [PATCH 174/376] s3:smb2_lock: handle NT_STATUS_RETRY from the VFS backend This allows the VFS backends to implement async byte range locking. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 7471b0f63276e707784c98b832992ff08b1898ef) --- source3/smbd/smb2_lock.c | 80 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 8ba54fe6995..26de8b521ed 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -44,6 +44,7 @@ struct smbd_smb2_lock_state { struct files_struct *fsp; bool blocking; uint32_t polling_msecs; + uint32_t retry_msecs; uint16_t lock_count; struct smbd_lock_element *locks; }; @@ -372,6 +373,33 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return req; } +static void smbd_smb2_lock_update_retry_msecs( + struct smbd_smb2_lock_state *state) +{ + /* + * The default lp_lock_spin_time() is 200ms, + * we just use half of it to trigger the first retry. + * + * v_min is in the range of 0.001 to 10 secs + * (0.1 secs by default) + * + * v_max is in the range of 0.01 to 100 secs + * (1.0 secs by default) + * + * The typical steps are: + * 0.1, 0.2, 0.3, 0.4, ... 1.0 + */ + uint32_t v_min = MAX(2, MIN(20000, lp_lock_spin_time()))/2; + uint32_t v_max = 10 * v_min; + + if (state->retry_msecs >= v_max) { + state->retry_msecs = v_max; + return; + } + + state->retry_msecs += v_min; +} + static void smbd_smb2_lock_update_polling_msecs( struct smbd_smb2_lock_state *state) { @@ -429,6 +457,51 @@ static void smbd_smb2_lock_try(struct tevent_req *req) tevent_req_done(req); return; } + if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { + /* + * We got NT_STATUS_RETRY, + * we reset polling_msecs so that + * that the retries based on LOCK_NOT_GRANTED + * will later start with small intervalls again. + */ + state->polling_msecs = 0; + + /* + * The backend wasn't able to decide yet. + * We need to wait even for non-blocking + * locks. + * + * The backend uses blocking_smblctx == UINT64_MAX + * to indicate that we should use retry timers. + * + * It uses blocking_smblctx == 0 to indicate + * it will use share_mode_wakeup_waiters() + * to wake us. Note that unrelated changes in + * locking.tdb may cause retries. + */ + + if (blocking_smblctx != UINT64_MAX) { + SMB_ASSERT(blocking_smblctx == 0); + goto setup_retry; + } + + smbd_smb2_lock_update_retry_msecs(state); + + DBG_DEBUG("Waiting for a backend decision. " + "Retry in %"PRIu32" msecs\n", + state->retry_msecs); + + /* + * We completely ignore state->endtime here + * we we'll wait for a backend decision forever. + * If the backend is smart enough to implement + * some NT_STATUS_RETRY logic, it has to + * switch to any other status after in order + * to avoid waiting forever. + */ + endtime = timeval_current_ofs_msec(state->retry_msecs); + goto setup_retry; + } if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { /* * This is a bug and will be changed into an assert @@ -447,6 +520,12 @@ static void smbd_smb2_lock_try(struct tevent_req *req) tevent_req_nterror(req, status); return; } + /* + * We got LOCK_NOT_GRANTED, make sure + * a following STATUS_RETRY will start + * with short intervalls again. + */ + state->retry_msecs = 0; if (!state->blocking) { TALLOC_FREE(lck); @@ -463,6 +542,7 @@ static void smbd_smb2_lock_try(struct tevent_req *req) endtime = timeval_current_ofs_msec(state->polling_msecs); } +setup_retry: DBG_DEBUG("Watching share mode lock\n"); subreq = dbwrap_watched_watch_send( -- 2.17.1 From ec21e68912d2c9b1f4c3aa57d9b34db038a6b66c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 8 Aug 2019 19:26:28 +0200 Subject: [PATCH 175/376] s3:locking: add brl_req_guid() and brl_req_mem_ctx() helper functions This allows the vfs backend to detect a retry and keep state between the retries. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 66d92f37c3a643d97489a59bb6d1e75e91528c20) --- source3/include/locking.h | 2 ++ source3/locking/brlock.c | 45 +++++++++++++++++++++++++++++++++---- source3/locking/locking.c | 11 ++++++++- source3/locking/proto.h | 8 +++++++ source3/modules/vfs_fruit.c | 13 +++++++++++ source3/smbd/blocking.c | 2 ++ source3/smbd/globals.c | 18 +++++++++++++++ source3/smbd/globals.h | 2 ++ source3/smbd/reply.c | 7 ++++++ source3/smbd/smb2_lock.c | 1 + source3/smbd/trans2.c | 2 ++ 11 files changed, 106 insertions(+), 5 deletions(-) diff --git a/source3/include/locking.h b/source3/include/locking.h index 3e7560bef9e..0175db2dd47 100644 --- a/source3/include/locking.h +++ b/source3/include/locking.h @@ -30,6 +30,7 @@ enum brl_type {READ_LOCK, WRITE_LOCK, UNLOCK_LOCK}; enum brl_flavour {WINDOWS_LOCK = 0, POSIX_LOCK = 1}; #include "librpc/gen_ndr/server_id.h" +#include "librpc/gen_ndr/misc.h" /* This contains elements that differentiate locks. The smbpid is a client supplied pid, and is essentially the locking context for @@ -62,6 +63,7 @@ struct lock_struct { }; struct smbd_lock_element { + struct GUID req_guid; uint64_t smblctx; enum brl_type brltype; uint64_t offset; diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index 0a85bd0b057..f22580164f9 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -46,6 +46,8 @@ static struct db_context *brlock_db; struct byte_range_lock { struct files_struct *fsp; + TALLOC_CTX *req_mem_ctx; + const struct GUID *req_guid; unsigned int num_locks; bool modified; struct lock_struct *lock_data; @@ -84,6 +86,25 @@ struct files_struct *brl_fsp(struct byte_range_lock *brl) return brl->fsp; } +TALLOC_CTX *brl_req_mem_ctx(const struct byte_range_lock *brl) +{ + if (brl->req_mem_ctx == NULL) { + return talloc_get_type_abort(brl, struct byte_range_lock); + } + + return brl->req_mem_ctx; +} + +const struct GUID *brl_req_guid(const struct byte_range_lock *brl) +{ + if (brl->req_guid == NULL) { + static const struct GUID brl_zero_req_guid; + return &brl_zero_req_guid; + } + + return brl->req_guid; +} + /**************************************************************************** See if two locking contexts are equal. ****************************************************************************/ @@ -1823,6 +1844,25 @@ struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp) return br_lck; } +struct byte_range_lock *brl_get_locks_for_locking(TALLOC_CTX *mem_ctx, + files_struct *fsp, + TALLOC_CTX *req_mem_ctx, + const struct GUID *req_guid) +{ + struct byte_range_lock *br_lck = NULL; + + br_lck = brl_get_locks(mem_ctx, fsp); + if (br_lck == NULL) { + return NULL; + } + SMB_ASSERT(req_mem_ctx != NULL); + br_lck->req_mem_ctx = req_mem_ctx; + SMB_ASSERT(req_guid != NULL); + br_lck->req_guid = req_guid; + + return br_lck; +} + struct brl_get_locks_readonly_state { TALLOC_CTX *mem_ctx; struct byte_range_lock **br_lock; @@ -1884,14 +1924,11 @@ struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp) /* * No locks on this file. Return an empty br_lock. */ - br_lock = talloc(fsp, struct byte_range_lock); + br_lock = talloc_zero(fsp, struct byte_range_lock); if (br_lock == NULL) { return NULL; } - br_lock->num_locks = 0; - br_lock->lock_data = NULL; - } else if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("Could not parse byte range lock record: " "%s\n", nt_errstr(status))); diff --git a/source3/locking/locking.c b/source3/locking/locking.c index d87a882d14f..8fa1237d6ad 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -232,6 +232,8 @@ static void decrement_current_lock_count(files_struct *fsp, struct do_lock_state { struct files_struct *fsp; + TALLOC_CTX *req_mem_ctx; + const struct GUID *req_guid; uint64_t smblctx; uint64_t count; uint64_t offset; @@ -251,7 +253,10 @@ static void do_lock_fn( struct do_lock_state *state = private_data; struct byte_range_lock *br_lck = NULL; - br_lck = brl_get_locks(talloc_tos(), state->fsp); + br_lck = brl_get_locks_for_locking(talloc_tos(), + state->fsp, + state->req_mem_ctx, + state->req_guid); if (br_lck == NULL) { state->status = NT_STATUS_NO_MEMORY; return; @@ -272,6 +277,8 @@ static void do_lock_fn( } NTSTATUS do_lock(files_struct *fsp, + TALLOC_CTX *req_mem_ctx, + const struct GUID *req_guid, uint64_t smblctx, uint64_t count, uint64_t offset, @@ -282,6 +289,8 @@ NTSTATUS do_lock(files_struct *fsp, { struct do_lock_state state = { .fsp = fsp, + .req_mem_ctx = req_mem_ctx, + .req_guid = req_guid, .smblctx = smblctx, .count = count, .offset = offset, diff --git a/source3/locking/proto.h b/source3/locking/proto.h index 7cb8bf3e3c9..7cf681561bc 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -30,6 +30,8 @@ void brl_shutdown(void); unsigned int brl_num_locks(const struct byte_range_lock *brl); struct files_struct *brl_fsp(struct byte_range_lock *brl); +TALLOC_CTX *brl_req_mem_ctx(const struct byte_range_lock *brl); +const struct GUID *brl_req_guid(const struct byte_range_lock *brl); bool byte_range_valid(uint64_t ofs, uint64_t len); bool byte_range_overlap(uint64_t ofs1, @@ -76,6 +78,10 @@ int brl_forall(void (*fn)(struct file_id id, struct server_id pid, br_off start, br_off size, void *private_data), void *private_data); +struct byte_range_lock *brl_get_locks_for_locking(TALLOC_CTX *mem_ctx, + files_struct *fsp, + TALLOC_CTX *req_mem_ctx, + const struct GUID *req_guid); struct byte_range_lock *brl_get_locks(TALLOC_CTX *mem_ctx, files_struct *fsp); struct byte_range_lock *brl_get_locks_readonly(files_struct *fsp); @@ -100,6 +106,8 @@ NTSTATUS query_lock(files_struct *fsp, enum brl_type *plock_type, enum brl_flavour lock_flav); NTSTATUS do_lock(files_struct *fsp, + TALLOC_CTX *req_mem_ctx, + const struct GUID *req_guid, uint64_t smblctx, uint64_t count, uint64_t offset, diff --git a/source3/modules/vfs_fruit.c b/source3/modules/vfs_fruit.c index 0be7f20e9af..85c7af21d58 100644 --- a/source3/modules/vfs_fruit.c +++ b/source3/modules/vfs_fruit.c @@ -2621,6 +2621,7 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, bool netatalk_already_open_for_writing = false; bool netatalk_already_open_with_deny_read = false; bool netatalk_already_open_with_deny_write = false; + struct GUID req_guid = GUID_random(); /* FIXME: hardcoded data fork, add resource fork */ enum apple_fork fork_type = APPLE_FORK_DATA; @@ -2684,8 +2685,11 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, /* Set NetAtalk locks matching our access */ if (access_mask & FILE_READ_DATA) { off = access_to_netatalk_brl(fork_type, FILE_READ_DATA); + req_guid.time_hi_and_version = __LINE__; status = do_lock( fsp, + talloc_tos(), + &req_guid, fsp->op->global->open_persistent_id, 1, off, @@ -2701,8 +2705,11 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, if (!share_for_read) { off = denymode_to_netatalk_brl(fork_type, DENY_READ); + req_guid.time_hi_and_version = __LINE__; status = do_lock( fsp, + talloc_tos(), + &req_guid, fsp->op->global->open_persistent_id, 1, off, @@ -2718,8 +2725,11 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, if (access_mask & FILE_WRITE_DATA) { off = access_to_netatalk_brl(fork_type, FILE_WRITE_DATA); + req_guid.time_hi_and_version = __LINE__; status = do_lock( fsp, + talloc_tos(), + &req_guid, fsp->op->global->open_persistent_id, 1, off, @@ -2735,8 +2745,11 @@ static NTSTATUS fruit_check_access(vfs_handle_struct *handle, if (!share_for_write) { off = denymode_to_netatalk_brl(fork_type, DENY_WRITE); + req_guid.time_hi_and_version = __LINE__; status = do_lock( fsp, + talloc_tos(), + &req_guid, fsp->op->global->open_persistent_id, 1, off, diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index fbd1ea812f3..94e75a9b405 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -45,6 +45,8 @@ NTSTATUS smbd_do_locks_try( status = do_lock( fsp, + locks, /* req_mem_ctx */ + &e->req_guid, e->smblctx, e->count, e->offset, diff --git a/source3/smbd/globals.c b/source3/smbd/globals.c index 6bc448b901d..0cdce20d122 100644 --- a/source3/smbd/globals.c +++ b/source3/smbd/globals.c @@ -109,3 +109,21 @@ void smbd_init_globals(void) ZERO_STRUCT(sec_ctx_stack); } + +struct GUID smbd_request_guid(struct smb_request *smb1req, uint16_t idx) +{ + struct GUID v = { + .time_low = (uint32_t)smb1req->mid, + .time_hi_and_version = idx, + }; + + if (smb1req->smb2req != NULL) { + v.time_mid = (uint16_t)smb1req->smb2req->current_idx; + } else { + v.time_mid = (uint16_t)(uintptr_t)smb1req->vwv; + } + + SBVAL((uint8_t *)&v, 8, (uintptr_t)smb1req->xconn); + + return v; +} diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 03d50882d16..47916ba29a1 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -115,6 +115,8 @@ DATA_BLOB negprot_spnego(TALLOC_CTX *ctx, struct smbXsrv_connection *xconn); void smbd_lock_socket(struct smbXsrv_connection *xconn); void smbd_unlock_socket(struct smbXsrv_connection *xconn); +struct GUID smbd_request_guid(struct smb_request *smb1req, uint16_t idx); + NTSTATUS smbd_do_unlocking(struct smb_request *req, files_struct *fsp, uint16_t num_ulocks, diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 2622681a2da..dec67a10cae 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3842,6 +3842,7 @@ void reply_lockread(struct smb_request *req) */ *lck = (struct smbd_lock_element) { + .req_guid = smbd_request_guid(req, 0), .smblctx = req->smbpid, .brltype = WRITE_LOCK, .count = SVAL(req->vwv+1, 0), @@ -4869,6 +4870,7 @@ void reply_writeunlock(struct smb_request *req) if (numtowrite && !fsp->print_file) { struct smbd_lock_element l = { + .req_guid = smbd_request_guid(req, 0), .smblctx = req->smbpid, .brltype = UNLOCK_LOCK, .offset = startpos, @@ -5764,6 +5766,7 @@ void reply_lock(struct smb_request *req) } *lck = (struct smbd_lock_element) { + .req_guid = smbd_request_guid(req, 0), .smblctx = req->smbpid, .brltype = WRITE_LOCK, .count = IVAL(req->vwv+1, 0), @@ -5855,6 +5858,7 @@ void reply_unlock(struct smb_request *req) } lck = (struct smbd_lock_element) { + .req_guid = smbd_request_guid(req, 0), .smblctx = req->smbpid, .brltype = UNLOCK_LOCK, .offset = IVAL(req->vwv+3, 0), @@ -8433,6 +8437,8 @@ void reply_lockingX(struct smb_request *req) * smb_unlkrng structs */ for (i = 0; i < num_ulocks; i++) { + ulocks[i].req_guid = smbd_request_guid(req, + UINT16_MAX - i), ulocks[i].smblctx = get_lock_pid( data, i, large_file_format); ulocks[i].count = get_lock_count( @@ -8490,6 +8496,7 @@ void reply_lockingX(struct smb_request *req) } for (i = 0; i < num_locks; i++) { + locks[i].req_guid = smbd_request_guid(req, i), locks[i].smblctx = get_lock_pid(data, i, large_file_format); locks[i].count = get_lock_count(data, i, large_file_format); locks[i].offset = get_lock_offset(data, i, large_file_format); diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 26de8b521ed..381aae6cb60 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -318,6 +318,7 @@ static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } + locks[i].req_guid = smbd_request_guid(smb2req->smb1req, i); locks[i].smblctx = fsp->op->global->open_persistent_id; locks[i].offset = in_locks[i].offset; locks[i].count = in_locks[i].length; diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 5b99240e9e8..0539b35bb73 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -7572,6 +7572,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, if (lock_type == UNLOCK_LOCK) { struct smbd_lock_element l = { + .req_guid = smbd_request_guid(req, 0), .smblctx = smblctx, .brltype = UNLOCK_LOCK, .offset = offset, @@ -7587,6 +7588,7 @@ static NTSTATUS smb_set_posix_lock(connection_struct *conn, } *lck = (struct smbd_lock_element) { + .req_guid = smbd_request_guid(req, 0), .smblctx = smblctx, .brltype = lock_type, .count = count, -- 2.17.1 From 9bf1c5c3e48ff905eec6f9ee469f1067b4105d42 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 19 Aug 2019 18:22:38 +0200 Subject: [PATCH 176/376] vfs_delay_inject: add support for brl_[un]lock_windows() This demonstrates the two ways to handle the retry: - smb layer retry => plock->context.smblctx = UINT64_MAX - vfs backend retry => plock->context.smblctx = 0 BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit c2503a5c68e967054ab84ca0d8ce693200c2e002) --- source3/modules/vfs_delay_inject.c | 117 +++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/source3/modules/vfs_delay_inject.c b/source3/modules/vfs_delay_inject.c index d561fadb03b..569bd40054a 100644 --- a/source3/modules/vfs_delay_inject.c +++ b/source3/modules/vfs_delay_inject.c @@ -304,12 +304,129 @@ static ssize_t vfs_delay_inject_pwrite_recv(struct tevent_req *req, return state->ret; } +struct vfs_delay_inject_brl_lock_state { + struct vfs_delay_inject_brl_lock_state *prev, *next; + struct files_struct *fsp; + struct GUID req_guid; + struct timeval delay_tv; + struct tevent_timer *delay_te; +}; + +static struct vfs_delay_inject_brl_lock_state *brl_lock_states; + +static int vfs_delay_inject_brl_lock_state_destructor(struct vfs_delay_inject_brl_lock_state *state) +{ + DLIST_REMOVE(brl_lock_states, state); + return 0; +} + +static void vfs_delay_inject_brl_lock_timer(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval current_time, + void *private_data) +{ + struct vfs_delay_inject_brl_lock_state *state = + talloc_get_type_abort(private_data, + struct vfs_delay_inject_brl_lock_state); + NTSTATUS status; + + TALLOC_FREE(state->delay_te); + + status = share_mode_wakeup_waiters(state->fsp->file_id); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("share_mode_wakeup_waiters(%s) %s\n", + file_id_string_tos(&state->fsp->file_id), + nt_errstr(status)); + } +} + +static NTSTATUS vfs_delay_inject_brl_lock_windows(struct vfs_handle_struct *handle, + struct byte_range_lock *br_lck, + struct lock_struct *plock) +{ + struct files_struct *fsp = brl_fsp(br_lck); + TALLOC_CTX *req_mem_ctx = brl_req_mem_ctx(br_lck); + const struct GUID *req_guid = brl_req_guid(br_lck); + struct vfs_delay_inject_brl_lock_state *state = NULL; + bool expired; + + for (state = brl_lock_states; state != NULL; state = state->next) { + bool match; + + match = GUID_equal(&state->req_guid, req_guid); + if (match) { + break; + } + } + + if (state == NULL) { + int delay; + bool use_timer; + + state = talloc_zero(req_mem_ctx, + struct vfs_delay_inject_brl_lock_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->fsp = fsp; + state->req_guid = *req_guid; + + delay = lp_parm_int(SNUM(handle->conn), + "delay_inject", "brl_lock_windows", 0); + state->delay_tv = timeval_current_ofs_msec(delay); + + use_timer = lp_parm_bool(SNUM(handle->conn), + "delay_inject", "brl_lock_windows_use_timer", true); + + if (use_timer) { + state->delay_te = tevent_add_timer( + global_event_context(), + state, + state->delay_tv, + vfs_delay_inject_brl_lock_timer, + state); + if (state->delay_te == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + + talloc_set_destructor(state, + vfs_delay_inject_brl_lock_state_destructor); + DLIST_ADD_END(brl_lock_states, state); + } + + if (state->delay_te != NULL) { + plock->context.smblctx = 0; + return NT_STATUS_RETRY; + } + + expired = timeval_expired(&state->delay_tv); + if (!expired) { + plock->context.smblctx = UINT64_MAX; + return NT_STATUS_RETRY; + } + + TALLOC_FREE(state); + + return SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle, br_lck, plock); +} + +static bool vfs_delay_inject_brl_unlock_windows(struct vfs_handle_struct *handle, + struct byte_range_lock *br_lck, + const struct lock_struct *plock) +{ + return SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle, br_lck, plock); +} + static struct vfs_fn_pointers vfs_delay_inject_fns = { .ntimes_fn = vfs_delay_inject_ntimes, .pread_send_fn = vfs_delay_inject_pread_send, .pread_recv_fn = vfs_delay_inject_pread_recv, .pwrite_send_fn = vfs_delay_inject_pwrite_send, .pwrite_recv_fn = vfs_delay_inject_pwrite_recv, + + .brl_lock_windows_fn = vfs_delay_inject_brl_lock_windows, + .brl_unlock_windows_fn = vfs_delay_inject_brl_unlock_windows, }; static_decl_vfs; -- 2.17.1 From be42cfafee057993d038f7d476d094c53b00b57e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 20 Aug 2019 15:53:59 +0200 Subject: [PATCH 177/376] s3:selftest: add delay_inject:brl_lock_windows testing BUG: https://bugzilla.samba.org/show_bug.cgi?id=14113 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Mon Sep 9 15:42:45 UTC 2019 on sn-devel-184 (cherry picked from commit 2b43ce6704ecf035e6734337a2dea3458153a4b2) Autobuild-User(v4-11-test): Stefan Metzmacher Autobuild-Date(v4-11-test): Mon Sep 9 17:19:11 UTC 2019 on sn-devel-184 --- selftest/target/Samba3.pm | 12 ++++++++++++ source3/selftest/tests.py | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 9638bb44f08..131d576a767 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -2263,6 +2263,18 @@ sub provision($$$$$$$$$) delay_inject:pread_send = 2000 delay_inject:pwrite_send = 2000 +[brl_delay_inject1] + copy = tmp + vfs objects = delay_inject + delay_inject:brl_lock_windows = 90 + delay_inject:brl_lock_windows_use_timer = yes + +[brl_delay_inject2] + copy = tmp + vfs objects = delay_inject + delay_inject:brl_lock_windows = 90 + delay_inject:brl_lock_windows_use_timer = no + [delete_readonly] path = $prefix_abs/share delete readonly = yes diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index ebc366de3ea..31cb8ca33f1 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -531,6 +531,10 @@ for t in tests: plansmbtorture4testsuite(t, env, '//$SERVER/tmp -k no -U$DC_USERNAME@$REALM%$DC_PASSWORD', description='ntlm user@realm') elif t == "raw.samba3posixtimedlock" or t == "smb2.samba3misc": plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share') + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/brl_delay_inject1 -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share', + description="brl_delay_inject1") + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/brl_delay_inject2 -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/nt4_dc/share', + description="brl_delay_inject2") plansmbtorture4testsuite(t, "ad_dc", '//$SERVER_IP/tmpguest -U$USERNAME%$PASSWORD --option=torture:localdir=$SELFTEST_PREFIX/ad_dc/share') elif t == "raw.chkpath": plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmpcase -U$USERNAME%$PASSWORD') -- 2.17.1 From 02ccbe08a53e385460d17b54bbabee5a362e1a5b Mon Sep 17 00:00:00 2001 From: Evgeny Sinelnikov Date: Wed, 31 Jul 2019 23:17:20 +0400 Subject: [PATCH 178/376] s3:ldap: Fix join with don't exists machine account MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add check for requested replies of existing machine object during join machine to domain. This solves regression fail during join with error: "None of the information to be translated has been translated." https://bugzilla.samba.org/show_bug.cgi?id=14007 Reviewed-by: Guenther Deschner Reviewed-by: Alexander Bokovoy Reviewed-by: Stefan Metzmacher Autobuild-User(master): Günther Deschner Autobuild-Date(master): Wed Sep 4 17:02:37 UTC 2019 on sn-devel-184 (cherry picked from commit ad4ef1657e9b2a088a3bfadcce196cfcceead1dc) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Tue Sep 10 09:13:15 UTC 2019 on sn-devel-184 --- source3/libads/ldap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 4f3d43b02b1..2110390b65f 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -2121,13 +2121,14 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, } ret = ads_find_machine_acct(ads, &res, machine_escaped); - ads_msgfree(ads, res); - if (ADS_ERR_OK(ret)) { + if (ADS_ERR_OK(ret) && ads_count_replies(ads, res) == 1) { DBG_DEBUG("Host account for %s already exists.\n", machine_escaped); ret = ADS_ERROR_LDAP(LDAP_ALREADY_EXISTS); + ads_msgfree(ads, res); goto done; } + ads_msgfree(ads, res); new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_escaped, org_unit); samAccountName = talloc_asprintf(ctx, "%s$", machine_name); -- 2.17.1 From 0318b68675d0318027ff5b6abf4a0d010839e6fd Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 30 Aug 2019 14:49:24 +0200 Subject: [PATCH 179/376] s4:torture: add a file-id related test Note I'm using the share vfs_fruit_xattr because I need a share with both a streams and a acl_* VFS object. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit 2ecab3c60abf9baa16a6a5e3eba0fc4720def840) --- selftest/knownfail.d/samba3.smb2.create | 1 + source3/selftest/tests.py | 2 + source4/selftest/tests.py | 1 + source4/torture/smb2/create.c | 212 ++++++++++++++++++++++++ source4/torture/smb2/smb2.c | 1 + 5 files changed, 217 insertions(+) create mode 100644 selftest/knownfail.d/samba3.smb2.create diff --git a/selftest/knownfail.d/samba3.smb2.create b/selftest/knownfail.d/samba3.smb2.create new file mode 100644 index 00000000000..89455dacdf0 --- /dev/null +++ b/selftest/knownfail.d/samba3.smb2.create @@ -0,0 +1 @@ +^samba3.smb2.fileid.fileid\(nt4_dc\) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 31cb8ca33f1..20f2eea7661 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -689,6 +689,8 @@ for t in tests: plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD') plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/delete_readonly -U$USERNAME%$PASSWORD --option=torture:delete_readonly=true') plansmbtorture4testsuite(t, "ad_dc", '//$SERVER/tmp -U$USERNAME%$PASSWORD') + elif t == "smb2.fileid": + plansmbtorture4testsuite(t, "nt4_dc", '//$SERVER_IP/vfs_fruit_xattr -U$USERNAME%$PASSWORD') elif t == "rpc.wkssvc": plansmbtorture4testsuite(t, "ad_member", '//$SERVER/tmp -U$DC_USERNAME%$DC_PASSWORD') elif t == "rpc.srvsvc": diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index bf3dd98cbef..3f55649f217 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -342,6 +342,7 @@ smb2_s3only = [ "smb2.kernel-oplocks", "smb2.durable-v2-delay", "smb2.aio_delay", + "smb2.fileid", ] smb2 = [x for x in smbtorture4_testsuites("smb2.") if x not in smb2_s3only] diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index 9b32062ab07..beddefc4c8d 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -1905,6 +1905,204 @@ done: return ret; } +static bool test_fileid(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *fname = DNAME "\\foo"; + const char *sname = DNAME "\\foo:bar"; + struct smb2_handle testdirh; + struct smb2_handle h1; + struct smb2_create create; + union smb_fileinfo finfo; + union smb_setfileinfo sinfo; + struct smb2_find f; + unsigned int count; + union smb_search_data *d; + uint64_t fileid; + uint64_t stream_fileid; + NTSTATUS status; + bool ret = true; + + smb2_deltree(tree, DNAME); + + status = torture_smb2_testdir(tree, DNAME, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir failed\n"); + + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN_IF, + .in.fname = fname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + + fileid = BVAL(&create.out.on_disk_id, 0); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + ret, done, "bad fileid\n"); + + f = (struct smb2_find) { + .in.file.handle = testdirh, + .in.pattern = "foo", + .in.max_response_size = 0x1000, + .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + }; + + status = smb2_find_level(tree, tree, &f, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_find_level failed\n"); + + torture_assert_u64_equal_goto(tctx, + d->id_both_directory_info.file_id, + fileid, + ret, done, "bad fileid\n"); + + smb2_util_close(tree, h1); + + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF, + .in.fname = sname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + + stream_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, stream_fileid, fileid, + ret, done, "bad fileid\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + ret, done, "bad fileid\n"); + + f = (struct smb2_find) { + .in.file.handle = testdirh, + .in.pattern = "foo", + .in.max_response_size = 0x1000, + .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART, + }; + + status = smb2_find_level(tree, tree, &f, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_find_level failed\n"); + + torture_assert_u64_equal_goto(tctx, + d->id_both_directory_info.file_id, + fileid, + ret, done, "bad fileid\n"); + + status = smb2_util_write(tree, h1, "foo", 0, strlen("foo")); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + sinfo = (union smb_setfileinfo) { + .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION, + .basic_info.in.file.handle = h1, + }; + unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL)); + + status = smb2_setinfo_file(tree, &sinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + ret, done, "bad fileid\n"); + + smb2_util_close(tree, h1); + + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = fname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + ret, done, "bad fileid\n"); + + f = (struct smb2_find) { + .in.file.handle = testdirh, + .in.pattern = "foo", + .in.max_response_size = 0x1000, + .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART, + }; + + status = smb2_find_level(tree, tree, &f, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_find_level failed\n"); + + torture_assert_u64_equal_goto(tctx, + d->id_both_directory_info.file_id, + fileid, + ret, done, "bad fileid\n"); + + smb2_util_close(tree, h1); + +done: + smb2_util_close(tree, testdirh); + smb2_deltree(tree, DNAME); + talloc_free(mem_ctx); + return ret; +} + /* basic testing of SMB2 read */ @@ -1942,3 +2140,17 @@ struct torture_suite *torture_smb2_twrp_init(TALLOC_CTX *ctx) return suite; } + +/* + basic testing of SMB2 File-IDs +*/ +struct torture_suite *torture_smb2_fileid_init(TALLOC_CTX *ctx) +{ + struct torture_suite *suite = torture_suite_create(ctx, "fileid"); + + torture_suite_add_1smb2_test(suite, "fileid", test_fileid); + + suite->description = talloc_strdup(suite, "SMB2-CREATE tests"); + + return suite; +} diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c index e57dba3c1d9..7cca19e65d3 100644 --- a/source4/torture/smb2/smb2.c +++ b/source4/torture/smb2/smb2.c @@ -155,6 +155,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx) torture_suite_add_suite(suite, torture_smb2_aio_delay_init(suite)); torture_suite_add_suite(suite, torture_smb2_create_init(suite)); torture_suite_add_suite(suite, torture_smb2_twrp_init(suite)); + torture_suite_add_suite(suite, torture_smb2_fileid_init(suite)); torture_suite_add_suite(suite, torture_smb2_acls_init(suite)); torture_suite_add_suite(suite, torture_smb2_notify_init(suite)); torture_suite_add_suite(suite, torture_smb2_notify_inotify_init(suite)); -- 2.17.1 From cca34da443ed6ee530fcf8c0def63d4b00527ffd Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 3 Sep 2019 17:50:54 +0200 Subject: [PATCH 180/376] lib: add round_timespec_to_nttime() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit 5403bb22e6cb39baf6dc1b91558744d41e9f6f64) --- lib/util/time.c | 9 +++++++++ lib/util/time.h | 1 + 2 files changed, 10 insertions(+) diff --git a/lib/util/time.c b/lib/util/time.c index bd067f84e8e..3a6043025f4 100644 --- a/lib/util/time.c +++ b/lib/util/time.c @@ -956,6 +956,15 @@ void round_timespec_to_usec(struct timespec *ts) } } +/**************************************************************************** + Round a timespec to NTTIME resolution. +****************************************************************************/ + +void round_timespec_to_nttime(struct timespec *ts) +{ + ts->tv_nsec = (ts->tv_nsec / 100) * 100; +} + /**************************************************************************** Put a 8 byte filetime from a struct timespec. Uses GMT. ****************************************************************************/ diff --git a/lib/util/time.h b/lib/util/time.h index 1988b330576..7a8f8af35d9 100644 --- a/lib/util/time.h +++ b/lib/util/time.h @@ -328,6 +328,7 @@ struct timespec timespec_min(const struct timespec *ts1, int timespec_compare(const struct timespec *ts1, const struct timespec *ts2); void round_timespec_to_sec(struct timespec *ts); void round_timespec_to_usec(struct timespec *ts); +void round_timespec_to_nttime(struct timespec *ts); NTTIME unix_timespec_to_nt_time(struct timespec ts); #endif /* _SAMBA_TIME_H_ */ -- 2.17.1 From 6dfeecf345c0a009fff6b233241156eff3160467 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 9 Sep 2019 11:12:08 +0200 Subject: [PATCH 181/376] s3:lib: round itime to NTTIME resolution in make_file_id_from_itime() The rounding is needed because when a file is created via eg an SMB2 CREATE request, we need to calculate the correct File-ID for the QFID Create-Context or for a subsequent GETINFO SMB request on the same file-handle. Any later metadata request that received the File-ID will do so by going through dos_mode() -> ... -> parse_dos_attribute_blob(), where the File-ID will be calculated from the on-disk itime which has NTTIME resolution. As long as that is the only available itime backend, I'm rounding itime inside make_file_id_from_itime(), not in the callers. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit 84abeaa60ffced276da2b28b8add6efaa6da5ca6) --- source3/lib/file_id.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source3/lib/file_id.c b/source3/lib/file_id.c index 7d4fb006afe..21f22ffbf3b 100644 --- a/source3/lib/file_id.c +++ b/source3/lib/file_id.c @@ -102,6 +102,8 @@ uint64_t make_file_id_from_itime(SMB_STRUCT_STAT *st) return ino; } + round_timespec_to_nttime(&itime); + file_id_low = itime.tv_nsec; if (file_id_low == 0) { /* -- 2.17.1 From d47f8ca1a769571dae73081cda6a01812c1a256c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 30 Aug 2019 14:48:40 +0200 Subject: [PATCH 182/376] s3:smbd: ensure to update the File-ID in struct smb_filename Initialize the File-ID in fsp->fsp_name->st, any subsequent metadata fetch on this file-handle needs this, eg QFID SMB2 Create-Context or GETINFO SMB requests. It would be nice if SMB_VFS_SET_DOS_ATTRIBUTE() would do this, unfortunately it gets a const struct smb_filename. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit 3483b75fed8985bd2968bbf8c85985107115fba8) --- source3/smbd/open.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 2ee4a2c4fca..a5650ac9c2d 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3710,6 +3710,15 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (info == FILE_WAS_CREATED) { smb_fname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME; + + if (lp_store_dos_attributes(SNUM(conn)) && + smb_fname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID) + { + uint64_t file_id; + + file_id = make_file_id_from_itime(&smb_fname->st); + update_stat_ex_file_id(&smb_fname->st, file_id); + } } if (info != FILE_WAS_OPENED) { @@ -3862,6 +3871,14 @@ static NTSTATUS mkdir_internal(connection_struct *conn, smb_dname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME; if (lp_store_dos_attributes(SNUM(conn))) { + if (smb_dname->st.st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID) + { + uint64_t file_id; + + file_id = make_file_id_from_itime(&smb_dname->st); + update_stat_ex_file_id(&smb_dname->st, file_id); + } + if (!posix_open) { file_set_dosmode(conn, smb_dname, file_attributes | FILE_ATTRIBUTE_DIRECTORY, -- 2.17.1 From 4930920648ad6879a72c77d79508025478dcbaa2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 30 Aug 2019 14:48:57 +0200 Subject: [PATCH 183/376] vfs_catia: stat info may have been updated, make sure to return changes BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit 4e49999c97f53acc7006f1dc6b6812bb0e156db5) --- source3/modules/vfs_catia.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index 762491ede31..1869d21dbcf 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -2377,6 +2377,10 @@ static NTSTATUS catia_get_dos_attributes(struct vfs_handle_struct *handle, status = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle, mapped_smb_fname, dosmode); + if (NT_STATUS_IS_OK(status)) { + smb_fname->st = mapped_smb_fname->st; + } + TALLOC_FREE(mapped_name); TALLOC_FREE(mapped_smb_fname); -- 2.17.1 From cb09104951cdefba991464e486c536b06356fd25 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 30 Aug 2019 14:49:47 +0200 Subject: [PATCH 184/376] s3:lib: add update_stat_ex_from_saved_stat() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit ac18730f10ce96a607a3a07e1360b522ebf72f38) --- source3/include/proto.h | 2 ++ source3/lib/system.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/source3/include/proto.h b/source3/include/proto.h index 8b387f7c563..ad6f3bbf9c3 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -223,6 +223,8 @@ void update_stat_ex_mtime(struct stat_ex *dst, struct timespec write_ts); void update_stat_ex_itime(struct stat_ex *dst, struct timespec itime); void update_stat_ex_create_time(struct stat_ex *dst, struct timespec create_time); void update_stat_ex_file_id(struct stat_ex *dst, uint64_t file_id); +void update_stat_ex_from_saved_stat(struct stat_ex *dst, + const struct stat_ex *src); int sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf, bool fake_dir_create_times); int sys_fstat(int fd, SMB_STRUCT_STAT *sbuf, diff --git a/source3/lib/system.c b/source3/lib/system.c index a67388e436a..0620439c944 100644 --- a/source3/lib/system.c +++ b/source3/lib/system.c @@ -355,6 +355,26 @@ void update_stat_ex_file_id(struct stat_ex *dst, uint64_t file_id) dst->st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_FILE_ID; } +void update_stat_ex_from_saved_stat(struct stat_ex *dst, + const struct stat_ex *src) +{ + if (!VALID_STAT(*src)) { + return; + } + + if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_BTIME)) { + update_stat_ex_create_time(dst, src->st_ex_btime); + } + + if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_ITIME)) { + update_stat_ex_itime(dst, src->st_ex_itime); + } + + if (!(src->st_ex_iflags & ST_EX_IFLAG_CALCULATED_FILE_ID)) { + update_stat_ex_file_id(dst, src->st_ex_file_id); + } +} + void init_stat_ex_from_stat (struct stat_ex *dst, const struct stat *src, bool fake_dir_create_times) -- 2.17.1 From b14dd975c754be30d247591190bec5db3f305245 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 9 Sep 2019 07:57:34 +0200 Subject: [PATCH 185/376] s3: replace fsp_stat() with vfs_stat_fsp() Both functions do the same, they differ just in the type of the returned result. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit ab03394969f8a4c748aea7d0d8ed37f9ced6cc30) --- source3/modules/vfs_dirsort.c | 13 ++++++++----- source3/smbd/fileio.c | 17 ----------------- source3/smbd/proto.h | 1 - source3/smbd/reply.c | 23 +++++++++++++++-------- 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/source3/modules/vfs_dirsort.c b/source3/modules/vfs_dirsort.c index c23f6f0152d..c6b5ea41c93 100644 --- a/source3/modules/vfs_dirsort.c +++ b/source3/modules/vfs_dirsort.c @@ -44,19 +44,22 @@ static bool get_sorted_dir_mtime(vfs_handle_struct *handle, { int ret; struct timespec mtime; + NTSTATUS status; if (data->fsp) { - ret = fsp_stat(data->fsp); + status = vfs_stat_fsp(data->fsp); + if (!NT_STATUS_IS_OK(status)) { + return false; + } mtime = data->fsp->fsp_name->st.st_ex_mtime; } else { ret = SMB_VFS_STAT(handle->conn, data->smb_fname); + if (ret == -1) { + return false; + } mtime = data->smb_fname->st.st_ex_mtime; } - if (ret == -1) { - return false; - } - *ret_mtime = mtime; return true; diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c index a00b368f92b..067ce5a9ad4 100644 --- a/source3/smbd/fileio.c +++ b/source3/smbd/fileio.c @@ -1068,20 +1068,3 @@ NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_throug } return NT_STATUS_OK; } - -/************************************************************ - Perform a stat whether a valid fd or not. -************************************************************/ - -int fsp_stat(files_struct *fsp) -{ - if (fsp->fh->fd == -1) { - if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) { - return SMB_VFS_LSTAT(fsp->conn, fsp->fsp_name); - } else { - return SMB_VFS_STAT(fsp->conn, fsp->fsp_name); - } - } else { - return SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); - } -} diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index cd1ec9a1f9e..10ffaf6e480 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -342,7 +342,6 @@ void delete_write_cache(files_struct *fsp); void set_filelen_write_cache(files_struct *fsp, off_t file_size); ssize_t flush_write_cache(files_struct *fsp, enum flush_reason_enum reason); NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_through); -int fsp_stat(files_struct *fsp); /* The following definitions come from smbd/filename.c */ diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index dec67a10cae..35d1ae772d5 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3662,6 +3662,7 @@ void reply_readbraw(struct smb_request *req) files_struct *fsp; struct lock_struct lock; off_t size = 0; + NTSTATUS status; START_PROFILE(SMBreadbraw); @@ -3759,7 +3760,8 @@ void reply_readbraw(struct smb_request *req) return; } - if (fsp_stat(fsp) == 0) { + status = vfs_stat_fsp(fsp); + if (NT_STATUS_IS_OK(status)) { size = fsp->fsp_name->st.st_ex_size; } @@ -4090,6 +4092,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, ssize_t nread = -1; struct lock_struct lock; int saved_errno = 0; + NTSTATUS status; init_strict_lock_struct(fsp, (uint64_t)req->smbpid, (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK, @@ -4114,8 +4117,9 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, uint8_t headerbuf[smb_size + 12 * 2 + 1 /* padding byte */]; DATA_BLOB header; - if(fsp_stat(fsp) == -1) { - reply_nterror(req, map_nt_error_from_unix(errno)); + status = vfs_stat_fsp(fsp); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); goto out; } @@ -5323,6 +5327,7 @@ void reply_lseek(struct smb_request *req) off_t res= -1; int mode,umode; files_struct *fsp; + NTSTATUS status; START_PROFILE(SMBlseek); @@ -5367,9 +5372,9 @@ void reply_lseek(struct smb_request *req) if(errno == EINVAL) { off_t current_pos = startpos; - if(fsp_stat(fsp) == -1) { - reply_nterror(req, - map_nt_error_from_unix(errno)); + status = vfs_stat_fsp(fsp); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBlseek); return; } @@ -8739,6 +8744,7 @@ void reply_getattrE(struct smb_request *req) int mode; files_struct *fsp; struct timespec create_ts; + NTSTATUS status; START_PROFILE(SMBgetattrE); @@ -8757,8 +8763,9 @@ void reply_getattrE(struct smb_request *req) } /* Do an fstat on this file */ - if(fsp_stat(fsp)) { - reply_nterror(req, map_nt_error_from_unix(errno)); + status = vfs_stat_fsp(fsp); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); END_PROFILE(SMBgetattrE); return; } -- 2.17.1 From b4aaa612d33caf51b44830d75997d4ad93b7740d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 9 Sep 2019 08:03:53 +0200 Subject: [PATCH 186/376] s3:vfs: streamline vfs_stat_fsp() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit e00e78cfeda99bd5374eff8fb4ba84873e4e46b7) --- source3/smbd/vfs.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 51a4aeb0f22..67f7d6356a2 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1413,13 +1413,11 @@ NTSTATUS vfs_stat_fsp(files_struct *fsp) } else { ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name); } - if (ret == -1) { - return map_nt_error_from_unix(errno); - } } else { - if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) { - return map_nt_error_from_unix(errno); - } + ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st); + } + if (ret == -1) { + return map_nt_error_from_unix(errno); } return NT_STATUS_OK; } -- 2.17.1 From d887047aa0c2489d1d6251ffcb9ce083e86866e1 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 9 Sep 2019 08:08:06 +0200 Subject: [PATCH 187/376] vfs: restore stat fields in vfs_stat_fsp() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ensures we preserve btime, itime and File-ID. As the Durable Handles code calls vfs_stat_fsp() in the DH disconnect function, previously the btime was lost and NOT stored in the cookie. With this change the cookie will store the correct btime (and iflags), which requires us to call dos_mode() in the reconnect function to ensure we pass vfs_default_durable_reconnect_check_stat(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14121 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Tue Sep 10 20:22:21 UTC 2019 on sn-devel-184 (cherry picked from commit 95655fe683d499d93f3844ed72ad332ef64adb96) Autobuild-User(v4-11-test): Stefan Metzmacher Autobuild-Date(v4-11-test): Tue Sep 10 22:29:08 UTC 2019 on sn-devel-184 --- selftest/knownfail.d/samba3.smb2.create | 1 - source3/smbd/durable.c | 2 ++ source3/smbd/vfs.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) delete mode 100644 selftest/knownfail.d/samba3.smb2.create diff --git a/selftest/knownfail.d/samba3.smb2.create b/selftest/knownfail.d/samba3.smb2.create deleted file mode 100644 index 89455dacdf0..00000000000 --- a/selftest/knownfail.d/samba3.smb2.create +++ /dev/null @@ -1 +0,0 @@ -^samba3.smb2.fileid.fileid\(nt4_dc\) diff --git a/source3/smbd/durable.c b/source3/smbd/durable.c index 4aa5a2d619e..89c4c1e8d14 100644 --- a/source3/smbd/durable.c +++ b/source3/smbd/durable.c @@ -842,6 +842,8 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn, return NT_STATUS_OBJECT_NAME_NOT_FOUND; } + (void)dos_mode(fsp->conn, fsp->fsp_name); + ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info, &fsp->fsp_name->st, fsp_str_dbg(fsp)); diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 67f7d6356a2..c8437a0c6c9 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1406,6 +1406,7 @@ int vfs_stat_smb_basename(struct connection_struct *conn, NTSTATUS vfs_stat_fsp(files_struct *fsp) { int ret; + struct stat_ex saved_stat = fsp->fsp_name->st; if(fsp->fh->fd == -1) { if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) { @@ -1419,6 +1420,7 @@ NTSTATUS vfs_stat_fsp(files_struct *fsp) if (ret == -1) { return map_nt_error_from_unix(errno); } + update_stat_ex_from_saved_stat(&fsp->fsp_name->st, &saved_stat); return NT_STATUS_OK; } -- 2.17.1 From 76eab3e6bc9631437719bf9a7fbabb8e77ceb20a Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 10 Sep 2019 13:02:12 +0200 Subject: [PATCH 188/376] WHATSNEW: Remove paragraph about rejoining DCs. Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 904db5fefc3..9069ca664ab 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -33,11 +33,6 @@ When either upgrading or downgrading, users should also avoid making any database modifications between installing the new Samba packages and starting the samba executable. -Note that when moving between major Samba releases in general, we recommend -that the AD DC is rejoined to the domain. Using this approach avoids the need -to explicitly downgrade the database manually. For more details, see: -https://wiki.samba.org/index.php/Upgrading_a_Samba_AD_DC - SMB1 is disabled by default --------------------------- -- 2.17.1 From 70906342a77e431e0ea5b482b9f35aa26a5d64bc Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 10 Sep 2019 09:19:32 +0200 Subject: [PATCH 189/376] WHATSNEW: Add release notes for Samba 4.11.0rc4. Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 9069ca664ab..74d1de4c021 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,7 +1,7 @@ Release Announcements ===================== -This is the third release candidate of Samba 4.11. This is *not* +This is the fourth release candidate of Samba 4.11. This is *not* intended for production environments and is designed for testing purposes only. Please report any defects via the Samba bug reporting system at https://bugzilla.samba.org/. @@ -368,6 +368,45 @@ smb.conf changes encrypt passwords Deprecated +CHANGES SINCE 4.11.0rc3 +======================= + +o Douglas Bagnall + * BUG 14049: ldb: Don't try to save a value that isn't there. + * ldb_dn: Free dn components on explode failure. + * ldb: Do not allow adding a DN as a base to itself. + +o Andrew Bartlett + * ldb: Release ldb 2.0.7. + * BUG 13695: ldb: Correct Pigeonhole principle validation in + ldb_filter_attrs(). + * BUG 14049: Fix ldb dn crash. + * BUG 14117: Deprecate "lanman auth = yes" and "encrypt passwords = no". + +o Ralph Boehme + * BUG 14038: Fix compiling ctdb on older systems lacking POSIX robust + mutexes. + * BUG 14121: smbd returns bad File-ID on filehandle used to create a file or + directory. + +o Poornima G + * BUG 14098: vfs_glusterfs: Use pthreadpool for scheduling aio operations. + +o Stefan Metzmacher + * BUG 14055: Add the target server name of SMB 3.1.1 connections as a hint to + load balancers or servers with "multi-tenancy" support. + * BUG 14113: Fix byte range locking bugs/regressions. + +o Swen Schillig + * ldb: Fix mem-leak if talloc_realloc fails. + +o Evgeny Sinelnikov + * BUG 14007: Fix join with don't exists machine account. + +o Martin Schwenke + * BUG 14085: ctdb-recoverd: Only check for LMASTER nodes in the VNN map. + + CHANGES SINCE 4.11.0rc2 ======================= -- 2.17.1 From b788d502cd187d1d71310ab9384e0b2445062491 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 10 Sep 2019 13:00:53 +0200 Subject: [PATCH 190/376] VERSION: Disable GIT_SNAPSHOT for the 4.11.0rc4 release. Signed-off-by: Karolin Seeger --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ae98c26560f..792dd684a3c 100644 --- a/VERSION +++ b/VERSION @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE=4 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=yes +SAMBA_VERSION_IS_GIT_SNAPSHOT=no ######################################################## # This is for specifying a release nickname # -- 2.17.1 From 4f2bbe2ed1d8d90c4c3311a8b77e1f695e66bea4 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 10 Sep 2019 13:19:03 +0200 Subject: [PATCH 191/376] VERSION: Bump version up to 4.11.0rc5... and re-enable GIT_SNAPSHOT. Signed-off-by: Karolin Seeger --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 792dd684a3c..e3cbecc1d16 100644 --- a/VERSION +++ b/VERSION @@ -87,7 +87,7 @@ SAMBA_VERSION_PRE_RELEASE= # e.g. SAMBA_VERSION_RC_RELEASE=1 # # -> "3.0.0rc1" # ######################################################## -SAMBA_VERSION_RC_RELEASE=4 +SAMBA_VERSION_RC_RELEASE=5 ######################################################## # To mark SVN snapshots this should be set to 'yes' # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE=4 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname # -- 2.17.1 From e0886709582a12b37cec4299172570169f986056 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 17 Sep 2019 10:00:54 +0200 Subject: [PATCH 192/376] WHATSNEW: Add release notes for Samba 4.11.0. Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 74d1de4c021..d573bb65819 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,12 +1,11 @@ -Release Announcements -===================== + ============================== + Release Notes for Samba 4.11.0 + September 17, 2019 + ============================== -This is the fourth release candidate of Samba 4.11. This is *not* -intended for production environments and is designed for testing -purposes only. Please report any defects via the Samba bug reporting -system at https://bugzilla.samba.org/. -Samba 4.11 will be the next version of the Samba suite. +This is the first stable release of the Samba 4.11 release series. +Please read the release notes carefully before upgrading. UPGRADING @@ -368,6 +367,10 @@ smb.conf changes encrypt passwords Deprecated +CHANGES SINCE 4.11.0rc4 +======================= + + CHANGES SINCE 4.11.0rc3 ======================= -- 2.17.1 From d60cf580825819f11de9e50ec4c4ce591d695ad9 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 17 Sep 2019 10:02:02 +0200 Subject: [PATCH 193/376] VERSION: Bump version up to 4.11.0... and disable GIT_SNAPSHOT for the 4.11.0 release. Signed-off-by: Karolin Seeger --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index e3cbecc1d16..29a4ca4e959 100644 --- a/VERSION +++ b/VERSION @@ -87,7 +87,7 @@ SAMBA_VERSION_PRE_RELEASE= # e.g. SAMBA_VERSION_RC_RELEASE=1 # # -> "3.0.0rc1" # ######################################################## -SAMBA_VERSION_RC_RELEASE=5 +SAMBA_VERSION_RC_RELEASE= ######################################################## # To mark SVN snapshots this should be set to 'yes' # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE=5 # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=yes +SAMBA_VERSION_IS_GIT_SNAPSHOT=no ######################################################## # This is for specifying a release nickname # -- 2.17.1 From 872e03c2dc859759fe17228068701865023b16b5 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 17 Sep 2019 10:03:08 +0200 Subject: [PATCH 194/376] VERSION: Bump version up to 4.11.1... and re-enable GIT_SNAPSHOT. Signed-off-by: Karolin Seeger --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 29a4ca4e959..137edf08bba 100644 --- a/VERSION +++ b/VERSION @@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=11 -SAMBA_VERSION_RELEASE=0 +SAMBA_VERSION_RELEASE=1 ######################################################## # If a official release has a serious bug # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname # -- 2.17.1 From a0342e92f3a25fbf15ab0f3ad3f05e597726be81 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 26 Aug 2019 09:54:06 -0700 Subject: [PATCH 195/376] s3: libsmbclient: Ensure SMBC_readdir_ctx() also updates the readdirplus pointers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we are returning file entries, we have a duplicate list in dirplus. Update dirplus_next also so readdir and readdirplus are kept in sync. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Böhme (cherry picked from commit 4bca8e097f5a909c628daa4dbfa932ddc1725ebc) --- source3/libsmb/libsmb_dir.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index 886aa626509..a3ec9a8ff71 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -1174,6 +1174,17 @@ SMBC_readdir_ctx(SMBCCTX *context, dir->dir_next = dir->dir_next->next; + /* + * If we are returning file entries, we + * have a duplicate list in dirplus. + * + * Update dirplus_next also so readdir and + * readdirplus are kept in sync. + */ + if (dir->dirplus_list != NULL) { + dir->dirplus_next = dir->dirplus_next->next; + } + TALLOC_FREE(frame); return dirp; } -- 2.17.1 From 0fbd2c08b548bd2588de960a5475ed5fc2de9bf7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 26 Aug 2019 10:02:47 -0700 Subject: [PATCH 196/376] s3: libsmbclient: Ensure SMBC_readdirplus_ctx() also updates the readdir pointers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we are returning file entries, we have a duplicate list in dir_list. Update dir_next also so readdir and readdirplus are kept in sync. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Böhme (cherry picked from commit 3d82b7d11cd7b78adc6b3642e64e3a8f251de869) --- source3/libsmb/libsmb_dir.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index a3ec9a8ff71..2f2117e8131 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -1231,6 +1231,17 @@ SMBC_readdirplus_ctx(SMBCCTX *context, } dir->dirplus_next = dir->dirplus_next->next; + /* + * If we are returning file entries, we + * have a duplicate list in dir_list + * + * Update dir_next also so readdir and + * readdirplus are kept in sync. + */ + if (dir->dir_list) { + dir->dir_next = dir->dir_next->next; + } + TALLOC_FREE(frame); return smb_finfo; } -- 2.17.1 From a70eee31213189d9cf0e4b40d14e2c301ef4f2c8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 26 Aug 2019 10:07:32 -0700 Subject: [PATCH 197/376] s3: libsmbclient: Ensure SMBC_getdents_ctx() also updates the readdirplus pointers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we are returning file entries, we have a duplicate list in dirplus. Update dirplus_next also so readdir and readdirplus are kept in sync. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Böhme (cherry picked from commit 754cec7756b2ddb1cfcc3984265f01cb366beb76) --- source3/libsmb/libsmb_dir.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index 2f2117e8131..4447806c108 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -1358,6 +1358,17 @@ SMBC_getdents_ctx(SMBCCTX *context, } dir->dir_next = dirlist = dirlist -> next; + + /* + * If we are returning file entries, we + * have a duplicate list in dirplus. + * + * Update dirplus_next also so readdir and + * readdirplus are kept in sync. + */ + if (dir->dirplus_list != NULL) { + dir->dirplus_next = dir->dirplus_next->next; + } } TALLOC_FREE(frame); -- 2.17.1 From 411eb45f2c9b9019d8a54c3c7092a3c0fc515e15 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 26 Aug 2019 10:18:28 -0700 Subject: [PATCH 198/376] s3: libsmbclient: Fix smbc_lseekdir() to work with smbc_readdirplus(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If returning files the dir_list and the dirplus_list have exactly the same entries, we just need to keep the next pointers in sync on seek. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Böhme (cherry picked from commit 0d9b1645499ce12a79a137d3482434aa5d2eb47c) --- source3/libsmb/libsmb_dir.c | 69 +++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/source3/libsmb/libsmb_dir.c b/source3/libsmb/libsmb_dir.c index 4447806c108..df606c4adfe 100644 --- a/source3/libsmb/libsmb_dir.c +++ b/source3/libsmb/libsmb_dir.c @@ -1672,35 +1672,43 @@ SMBC_telldir_ctx(SMBCCTX *context, /* * A routine to run down the list and see if the entry is OK + * Modifies the dir list and the dirplus list (if it exists) + * to point at the correct next entry on success. */ -static struct smbc_dir_list * -check_dir_ent(struct smbc_dir_list *list, - struct smbc_dirent *dirent) +static bool update_dir_ents(SMBCFILE *dir, struct smbc_dirent *dirent) { + struct smbc_dir_list *tmp_dir = dir->dir_list; + struct smbc_dirplus_list *tmp_dirplus = dir->dirplus_list; - /* Run down the list looking for what we want */ - - if (dirent) { - - struct smbc_dir_list *tmp = list; - - while (tmp) { - - if (tmp->dirent == dirent) - return tmp; - - tmp = tmp->next; + /* + * Run down the list looking for what we want. + * If we're enumerating files both dir_list + * and dirplus_list contain the same entry + * list, as they were seeded from the same + * cli_list callback. + * + * If we're enumerating servers then + * dirplus_list will be NULL, so don't + * update in that case. + */ + while (tmp_dir != NULL) { + if (tmp_dir->dirent == dirent) { + dir->dir_next = tmp_dir; + if (tmp_dirplus != NULL) { + dir->dirplus_next = tmp_dirplus; + } + return true; + } + tmp_dir = tmp_dir->next; + if (tmp_dirplus != NULL) { + tmp_dirplus = tmp_dirplus->next; } - } - - return NULL; /* Not found, or an error */ - + return false; } - /* * Routine to seek on a directory */ @@ -1712,8 +1720,8 @@ SMBC_lseekdir_ctx(SMBCCTX *context, { long int l_offset = offset; /* Handle problems of size */ struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset; - struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL; TALLOC_CTX *frame = talloc_stackframe(); + bool ok; if (!context || !context->internal->initialized) { @@ -1736,6 +1744,10 @@ SMBC_lseekdir_ctx(SMBCCTX *context, if (dirent == NULL) { /* Seek to the begining of the list */ dir->dir_next = dir->dir_list; + + /* Do the same for dirplus. */ + dir->dirplus_next = dir->dirplus_list; + TALLOC_FREE(frame); return 0; @@ -1743,21 +1755,26 @@ SMBC_lseekdir_ctx(SMBCCTX *context, if (offset == -1) { /* Seek to the end of the list */ dir->dir_next = NULL; + + /* Do the same for dirplus. */ + dir->dirplus_next = NULL; + TALLOC_FREE(frame); return 0; } - /* Now, run down the list and make sure that the entry is OK */ - /* This may need to be changed if we change the format of the list */ + /* + * Run down the list and make sure that the entry is OK. + * Update the position of both dir and dirplus lists. + */ - if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) { + ok = update_dir_ents(dir, dirent); + if (!ok) { errno = EINVAL; /* Bad entry */ TALLOC_FREE(frame); return -1; } - dir->dir_next = list_ent; - TALLOC_FREE(frame); return 0; } -- 2.17.1 From d702f66290159d72c8f3c5d08ec9e9f23772611f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 26 Aug 2019 11:22:35 -0700 Subject: [PATCH 199/376] s3/4: libsmbclient test. Test using smbc_telldir/smbc_lseekdir with smbc_readdir/smbc_readdirplus/smbc_getdents. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure that for file access you can mix any of these three access methods for directory entries and the returned names/structs stay in sync across telldir/seekdir changes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14094 Signed-off-by: Jeremy Allison Reviewed-by: Ralph Böhme Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Tue Sep 3 17:31:29 UTC 2019 on sn-devel-184 (cherry picked from commit 3355601fe8541994cc41f5ed800aab9b6a2294f4) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Wed Sep 18 13:51:56 UTC 2019 on sn-devel-184 --- source3/selftest/tests.py | 3 +- source4/torture/libsmbclient/libsmbclient.c | 340 ++++++++++++++++++++ 2 files changed, 342 insertions(+), 1 deletion(-) diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 20f2eea7661..5b5a1978988 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -495,7 +495,8 @@ nbt = ["nbt.dgram"] libsmbclient = ["libsmbclient.version", "libsmbclient.initialize", "libsmbclient.configuration", "libsmbclient.setConfiguration", "libsmbclient.options", "libsmbclient.opendir", - "libsmbclient.list_shares", "libsmbclient.readdirplus"] + "libsmbclient.list_shares", "libsmbclient.readdirplus", + "libsmbclient.readdirplus_seek"] vfs = [ "vfs.fruit", diff --git a/source4/torture/libsmbclient/libsmbclient.c b/source4/torture/libsmbclient/libsmbclient.c index f9154e8a19c..b74d87aabed 100644 --- a/source4/torture/libsmbclient/libsmbclient.c +++ b/source4/torture/libsmbclient/libsmbclient.c @@ -18,6 +18,7 @@ */ #include "includes.h" +#include "system/dir.h" #include "torture/smbtorture.h" #include "auth/credentials/credentials.h" #include "lib/cmdline/popt_common.h" @@ -375,6 +376,343 @@ static bool torture_libsmbclient_readdirplus(struct torture_context *tctx) return true; } +static bool torture_libsmbclient_readdirplus_seek(struct torture_context *tctx) +{ + SMBCCTX *ctx; + int ret = -1; + int dhandle = -1; + int fhandle = -1; + const char *dname = NULL; + const char *full_filename[100] = {0}; + const char *filename[100] = {0}; + const struct libsmb_file_info *direntries[102] = {0}; + unsigned int i = 0; + const char *smburl = torture_setting_string(tctx, "smburl", NULL); + bool success = false; + off_t telldir_50 = (off_t)-1; + off_t telldir_20 = (off_t)-1; + size_t getdentries_size = 0; + struct smbc_dirent *getdentries = NULL; + struct smbc_dirent *dirent_20 = NULL; + const struct libsmb_file_info *direntries_20 = NULL; + + if (smburl == NULL) { + torture_fail(tctx, + "option --option=torture:smburl=" + "smb://user:password@server/share missing\n"); + } + + DEBUG(0,("torture_libsmbclient_readdirplus_seek start\n")); + + torture_assert(tctx, torture_libsmbclient_init_context(tctx, &ctx), ""); + smbc_set_context(ctx); + + dname = talloc_asprintf(tctx, + "%s/rd_seek", + smburl); + if (dname == NULL) { + torture_fail_goto(tctx, + done, + "talloc fail\n"); + } + + /* Ensure the files don't exist. */ + for (i = 0; i < 100; i++) { + filename[i] = talloc_asprintf(tctx, + "test_readdirplus_%u.txt", + i); + if (filename[i] == NULL) { + torture_fail_goto(tctx, + done, + "talloc fail\n"); + } + full_filename[i] = talloc_asprintf(tctx, + "%s/%s", + dname, + filename[i]); + if (full_filename[i] == NULL) { + torture_fail_goto(tctx, + done, + "talloc fail\n"); + } + (void)smbc_unlink(full_filename[i]); + } + /* Ensure the directory doesn't exist. */ + (void)smbc_rmdir(dname); + + /* Create containing directory. */ + ret = smbc_mkdir(dname, 0777); + if (ret != 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "failed to create directory '%s': %s", + dname, + strerror(errno))); + } + + DEBUG(0,("torture_libsmbclient_readdirplus_seek create\n")); + + /* Create them. */ + for (i = 0; i < 100; i++) { + fhandle = smbc_creat(full_filename[i], 0666); + if (fhandle < 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "failed to create file '%s': %s", + full_filename[i], + strerror(errno))); + } + ret = smbc_close(fhandle); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to close handle for '%s'", + full_filename[i])); + } + + DEBUG(0,("torture_libsmbclient_readdirplus_seek enum\n")); + + /* Now enumerate the directory. */ + dhandle = smbc_opendir(dname); + if (dhandle < 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "failed to obtain " + "directory handle for '%s' : %s", + dname, + strerror(errno))); + } + + /* Read all the files. 100 we created plus . and .. */ + for (i = 0; i < 102; i++) { + bool found = false; + unsigned int j; + + direntries[i] = smbc_readdirplus(dhandle); + if (direntries[i] == NULL) { + break; + } + + /* Store at offset 50. */ + if (i == 50) { + telldir_50 = smbc_telldir(dhandle); + if (telldir_50 == (off_t)-1) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "telldir failed file %s\n", + direntries[i]->name)); + } + } + + if (ISDOT(direntries[i]->name)) { + continue; + } + if (ISDOTDOT(direntries[i]->name)) { + continue; + } + + /* Ensure all our files exist. */ + for (j = 0; j < 100; j++) { + if (strcmp(direntries[i]->name, + filename[j]) == 0) { + found = true; + } + } + if (!found) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "failed to find file %s\n", + direntries[i]->name)); + } + } + + /* + * We're seeking on in-memory lists here, so + * whilst the handle is open we really should + * get the same files back in the same order. + */ + + ret = smbc_lseekdir(dhandle, telldir_50); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to seek (50) directory handle for '%s'", + dname)); + + DEBUG(0,("torture_libsmbclient_readdirplus_seek seek\n")); + + for (i = 51; i < 102; i++) { + const struct libsmb_file_info *entry = + smbc_readdirplus(dhandle); + if (entry != direntries[i]) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "after seek - failed to find " + "file %s - got %s\n", + direntries[i]->name, + entry->name)); + } + } + + /* Seek back to the start. */ + ret = smbc_lseekdir(dhandle, 0); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to seek directory handle to start for '%s'", + dname)); + + /* + * Mix getdents/readdir/readdirplus with lseek to ensure + * we get the same result. + */ + + /* Allocate the space for 20 entries. + * Tricky as we need to allocate 20 struct smbc_dirent's + space + * for the name lengths. + */ + getdentries_size = 20 * (sizeof(struct smbc_dirent) + + strlen("test_readdirplus_1000.txt") + 1); + + getdentries = (struct smbc_dirent *)talloc_array_size(tctx, + getdentries_size, + 1); + + ret = smbc_getdents(dhandle, getdentries, getdentries_size); + torture_assert_goto(tctx, + (ret != -1), + success, + done, + talloc_asprintf(tctx, + "smbd_getdents(1) for '%s' failed\n", + dname)); + + telldir_20 = smbc_telldir(dhandle); + if (telldir_20 == (off_t)-1) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "telldir (20) failed\n")); + } + /* Read another 20. */ + ret = smbc_getdents(dhandle, getdentries, getdentries_size); + torture_assert_goto(tctx, + (ret != -1), + success, + done, + talloc_asprintf(tctx, + "smbd_getdents(2) for '%s' failed\n", + dname)); + + /* Seek back to 20. */ + ret = smbc_lseekdir(dhandle, telldir_20); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to seek (20) directory handle for '%s'", + dname)); + + /* Read with readdir. */ + dirent_20 = smbc_readdir(dhandle); + if (dirent_20 == NULL) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "smbc_readdir (20) failed\n")); + } + + /* Ensure the getdents and readdir names are the same. */ + ret = strcmp(dirent_20->name, getdentries[0].name); + if (ret != 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "after seek (20) readdir name missmatch " + "file %s - got %s\n", + dirent_20->name, + getdentries[0].name)); + } + + /* Seek back to 20. */ + ret = smbc_lseekdir(dhandle, telldir_20); + torture_assert_int_equal_goto(tctx, + ret, + 0, + success, + done, + talloc_asprintf(tctx, + "failed to seek (20) directory handle for '%s'", + dname)); + /* Read with readdirplus. */ + direntries_20 = smbc_readdirplus(dhandle); + if (direntries_20 == NULL) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "smbc_readdirplus (20) failed\n")); + } + + /* Ensure the readdirplus and readdir names are the same. */ + ret = strcmp(dirent_20->name, direntries_20->name); + if (ret != 0) { + torture_fail_goto(tctx, + done, + talloc_asprintf(tctx, + "after seek (20) readdirplus name missmatch " + "file %s - got %s\n", + dirent_20->name, + direntries_20->name)); + } + + ret = smbc_closedir(dhandle); + torture_assert_int_equal(tctx, + ret, + 0, + talloc_asprintf(tctx, + "failed to close directory handle for '%s'", + dname)); + + dhandle = -1; + success = true; + + done: + + /* Clean up. */ + if (dhandle != -1) { + smbc_closedir(dhandle); + } + for (i = 0; i < 100; i++) { + if (full_filename[i] != NULL) { + smbc_unlink(full_filename[i]); + } + } + if (dname != NULL) { + smbc_rmdir(dname); + } + + smbc_free_context(ctx, 1); + + return success; +} + bool torture_libsmbclient_configuration(struct torture_context *tctx) { SMBCCTX *ctx; @@ -635,6 +973,8 @@ NTSTATUS torture_libsmbclient_init(TALLOC_CTX *ctx) torture_suite_add_simple_test(suite, "list_shares", torture_libsmbclient_list_shares); torture_suite_add_simple_test(suite, "readdirplus", torture_libsmbclient_readdirplus); + torture_suite_add_simple_test(suite, "readdirplus_seek", + torture_libsmbclient_readdirplus_seek); suite->description = talloc_strdup(suite, "libsmbclient interface tests"); -- 2.17.1 From 4d41dc32653bd1ae7d87dcd5779c3586ae6561d3 Mon Sep 17 00:00:00 2001 From: Bryan Mason Date: Mon, 16 Sep 2019 12:35:06 -0700 Subject: [PATCH 200/376] s3:client:Use DEVICE_URI, instead of argv[0],for Device URI CUPS sanitizes argv[0] by removing username/password, so use DEVICE_URI environment variable first. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14128 Signed-off-by: Bryan Mason Reviewed-by: Alexander Bokovoy Reviewed-by: Andreas Schneider Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Wed Sep 18 12:31:11 UTC 2019 on sn-devel-184 (cherry picked from commit d65b17c3f7f9959ed95b03cc09e020d7387b7931) --- source3/client/smbspool.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/source3/client/smbspool.c b/source3/client/smbspool.c index ad988eb0df9..36f7f67ca94 100644 --- a/source3/client/smbspool.c +++ b/source3/client/smbspool.c @@ -256,13 +256,15 @@ main(int argc, /* I - Number of command-line arguments */ /* * Find the URI ... - */ - if (dev_uri == NULL) { - env = getenv("DEVICE_URI"); - if (env != NULL && env[0] != '\0') { - dev_uri = env; - } - } + * + * The URI in argv[0] is sanitized to remove username/password, so + * use DEVICE_URI if available. Otherwise keep the URI already + * discovered in argv. + */ + env = getenv("DEVICE_URI"); + if (env != NULL && env[0] != '\0') { + dev_uri = env; + } if (dev_uri == NULL) { fprintf(stderr, -- 2.17.1 From 361f4f5d24721d54558144a5905657d5cc7281a3 Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Tue, 13 Aug 2019 21:42:15 +1000 Subject: [PATCH 201/376] ctdb-tools: Stop deleted nodes from influencing ctdb nodestatus exit code Deleted nodes should simply be ignored. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14129 RN: Stop deleted nodes from influencing ctdb nodestatus exit code Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 32b5ceb31936ec5447362236c1809db003561d29) --- ctdb/tools/ctdb.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ctdb/tools/ctdb.c b/ctdb/tools/ctdb.c index 2cc72eedc76..6a15b61ccd1 100644 --- a/ctdb/tools/ctdb.c +++ b/ctdb/tools/ctdb.c @@ -5611,7 +5611,13 @@ static int control_nodestatus(TALLOC_CTX *mem_ctx, struct ctdb_context *ctdb, ret = 0; for (i=0; inum; i++) { - ret |= nodemap->node[i].flags; + uint32_t flags = nodemap->node[i].flags; + + if ((flags & NODE_FLAGS_DELETED) != 0) { + continue; + } + + ret |= flags; } return ret; -- 2.17.1 From d42c7ffa6cbd90d0e777e39b12eda5c69e186a2f Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Wed, 18 Sep 2019 03:15:47 +0000 Subject: [PATCH 202/376] pod2man is no longer needed Since e24e344d0da58013fd5fa404529fe1d25ef403bf. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14131 Signed-off-by: Mathieu Parent Reviewed-by: Martin Schwenke Reviewed-by: Andrew Bartlett (cherry picked from commit 8df123e7f7cb591f6673ccffefffc30b946f1a5b) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Fri Sep 20 21:13:55 UTC 2019 on sn-devel-184 --- pidl/wscript | 1 - 1 file changed, 1 deletion(-) diff --git a/pidl/wscript b/pidl/wscript index 01b71bd8b27..d1b8278990a 100644 --- a/pidl/wscript +++ b/pidl/wscript @@ -34,7 +34,6 @@ def configure(conf): # yapp is used for building the parser conf.find_program('yapp', var='YAPP') - conf.find_program('pod2man', var='POD2MAN') def build(bld): -- 2.17.1 From 18963e909d75785b27ea2fd0323fa8514b3e3198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= Date: Sat, 21 Sep 2019 13:24:59 +0200 Subject: [PATCH 203/376] classicupgrade: fix a a bytes-like object is required, not 'str' error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG: https://bugzilla.samba.org/show_bug.cgi?id=14136 Signed-off-by: Bjoern Jacke Reviewed-by: Björn Baumbach Autobuild-User(master): Björn Jacke Autobuild-Date(master): Mon Sep 23 12:58:20 UTC 2019 on sn-devel-184 (cherry picked from commit 465e518d6cc200eefa38643e720ce64e53abac2e) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Tue Sep 24 18:30:08 UTC 2019 on sn-devel-184 --- python/samba/upgrade.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/samba/upgrade.py b/python/samba/upgrade.py index 12555b7994e..8511bed2868 100644 --- a/python/samba/upgrade.py +++ b/python/samba/upgrade.py @@ -474,7 +474,7 @@ def upgrade_from_samba3(samba3, logger, targetdir, session_info=None, ldappass = secrets_db.get_ldap_bind_pw(ldapuser) if ldappass is None: raise ProvisioningError("ldapsam passdb backend detected but no LDAP Bind PW found in secrets.tdb for user %s. Please point this tool at the secrets.tdb that was used by the previous installation.") - ldappass = ldappass.strip('\x00') + ldappass = ldappass.decode('utf-8').strip('\x00') ldap = True else: ldapuser = None -- 2.17.1 From fa63860f7b1621e507c1950872444d366891384a Mon Sep 17 00:00:00 2001 From: Noel Power Date: Thu, 8 Aug 2019 15:06:28 +0100 Subject: [PATCH 204/376] s3/libads: clang: Fix Value stored to 'canon_princ' is never read Fixes: source3/libads/kerberos.c:192:2: warning: Value stored to 'canon_princ' is never read <--[clang] canon_princ = me; ^ ~~ 1 warning generated. Signed-off-by: Noel Power Reviewed-by: Gary Lockyer (cherry picked from commit 52d20087f620704549f5a5cdcbec79cb08a36290) --- source3/libads/kerberos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 721c3c2a929..9fbe7dd0f07 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -189,9 +189,10 @@ int kerberos_kinit_password_ext(const char *principal, goto out; } - canon_princ = me; #ifndef SAMBA4_USES_HEIMDAL /* MIT */ canon_princ = my_creds.client; +#else + canon_princ = me; #endif /* MIT */ if ((code = krb5_cc_initialize(ctx, cc, canon_princ))) { -- 2.17.1 From ed3ac77dc22572132667df2f2ba717cc16a8daa7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 18 Sep 2019 13:58:46 +0200 Subject: [PATCH 205/376] nsswitch: add logging to wbc_auth_error_to_pam_error() for non auth errors Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit acbf922fc2963a42d6cbe652bb32eee231020958) --- nsswitch/pam_winbind.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nsswitch/pam_winbind.c b/nsswitch/pam_winbind.c index 7841377fdd6..3ad70d3c4cd 100644 --- a/nsswitch/pam_winbind.c +++ b/nsswitch/pam_winbind.c @@ -862,6 +862,10 @@ static int wbc_auth_error_to_pam_error(struct pwb_context *ctx, } ret = wbc_error_to_pam_error(status); + _pam_log(ctx, LOG_ERR, + "request %s failed: %s, PAM error: %s (%d)!", + fn, wbcErrorString(status), + _pam_error_code_str(ret), ret); return pam_winbind_request_log(ctx, ret, username, fn); } -- 2.17.1 From 2ba8997d006eb6120ac3cf1917ba2b0e3b1a3d86 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 17 Sep 2019 08:05:09 +0200 Subject: [PATCH 206/376] s4:auth: use the correct client realm in gensec_gssapi_update_internal() The function gensec_gssapi_client_creds() may call kinit and gets a TGT for the user. The principal provided by the user may not be canonicalized. The user may use 'given.last@example.com' but that may be mapped to glast@AD.EXAMPLE.PRIVATE in the background. It means we should use client_realm = AD.EXAMPLE.PRIVATE instead of client_realm = EXAMPLE.COM BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit db8fd3d6a315b140ebd6ccd0dcdfdcf27cd1bb38) --- source4/auth/gensec/gensec_gssapi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 4577c91c93a..045a0225741 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -437,8 +437,6 @@ static NTSTATUS gensec_gssapi_update_internal(struct gensec_security *gensec_sec const char *target_principal = gensec_get_target_principal(gensec_security); const char *hostname = gensec_get_target_hostname(gensec_security); const char *service = gensec_get_target_service(gensec_security); - const char *client_realm = cli_credentials_get_realm(cli_creds); - const char *server_realm = NULL; gss_OID gss_oid_p = NULL; OM_uint32 time_req = 0; OM_uint32 time_rec = 0; @@ -457,6 +455,7 @@ static NTSTATUS gensec_gssapi_update_internal(struct gensec_security *gensec_sec switch (gensec_security->gensec_role) { case GENSEC_CLIENT: { + const char *client_realm = NULL; #ifdef SAMBA4_USES_HEIMDAL struct gsskrb5_send_to_kdc send_to_kdc; krb5_error_code ret; @@ -532,6 +531,7 @@ static NTSTATUS gensec_gssapi_update_internal(struct gensec_security *gensec_sec * transitive forest trusts, would have to do the * fallback ourself. */ + client_realm = cli_credentials_get_realm(cli_creds); #ifndef SAMBA4_USES_HEIMDAL if (gensec_gssapi_state->server_name == NULL) { nt_status = gensec_gssapi_setup_server_principal(gensec_gssapi_state, @@ -575,6 +575,8 @@ static NTSTATUS gensec_gssapi_update_internal(struct gensec_security *gensec_sec } #endif /* !SAMBA4_USES_HEIMDAL */ if (gensec_gssapi_state->server_name == NULL) { + const char *server_realm = NULL; + server_realm = smb_krb5_get_realm_from_hostname(gensec_gssapi_state, hostname, client_realm); -- 2.17.1 From f5ea5a5e2a5479b993cea335b73194b1c4cc6e76 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 16 Sep 2019 17:14:11 +0200 Subject: [PATCH 207/376] s3:libads: let kerberos_kinit_password_ext() return the canonicalized principal/realm BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit bc473e5cf088a137395842540ed8eb748373a236) --- source3/libads/authdata.c | 1 + source3/libads/kerberos.c | 46 ++++++++++++++++++++++---- source3/libads/kerberos_proto.h | 5 ++- source3/libads/kerberos_util.c | 3 +- source3/utils/net_ads.c | 3 ++ source3/winbindd/winbindd_cred_cache.c | 6 ++++ 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/source3/libads/authdata.c b/source3/libads/authdata.c index 86a1be71bf9..6e6d5b397ff 100644 --- a/source3/libads/authdata.c +++ b/source3/libads/authdata.c @@ -170,6 +170,7 @@ NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx, request_pac, add_netbios_addr, renewable_time, + NULL, NULL, NULL, &status); if (ret) { DEBUG(1,("kinit failed for '%s' with: %s (%d)\n", diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 9fbe7dd0f07..3e09d70268f 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -106,7 +106,7 @@ kerb_prompter(krb5_context ctx, void *data, place in default cache location. remus@snapserver.com */ -int kerberos_kinit_password_ext(const char *principal, +int kerberos_kinit_password_ext(const char *given_principal, const char *password, int time_offset, time_t *expire_time, @@ -115,8 +115,12 @@ int kerberos_kinit_password_ext(const char *principal, bool request_pac, bool add_netbios_addr, time_t renewable_time, + TALLOC_CTX *mem_ctx, + char **_canon_principal, + char **_canon_realm, NTSTATUS *ntstatus) { + TALLOC_CTX *frame = talloc_stackframe(); krb5_context ctx = NULL; krb5_error_code code = 0; krb5_ccache cc = NULL; @@ -125,6 +129,8 @@ int kerberos_kinit_password_ext(const char *principal, krb5_creds my_creds; krb5_get_init_creds_opt *opt = NULL; smb_krb5_addresses *addr = NULL; + char *canon_principal = NULL; + char *canon_realm = NULL; ZERO_STRUCT(my_creds); @@ -132,6 +138,7 @@ int kerberos_kinit_password_ext(const char *principal, if (code != 0) { DBG_ERR("kerberos init context failed (%s)\n", error_message(code)); + TALLOC_FREE(frame); return code; } @@ -139,16 +146,16 @@ int kerberos_kinit_password_ext(const char *principal, krb5_set_real_time(ctx, time(NULL) + time_offset, 0); } - DEBUG(10,("kerberos_kinit_password: as %s using [%s] as ccache and config [%s]\n", - principal, - cache_name ? cache_name: krb5_cc_default_name(ctx), - getenv("KRB5_CONFIG"))); + DBG_DEBUG("as %s using [%s] as ccache and config [%s]\n", + given_principal, + cache_name ? cache_name: krb5_cc_default_name(ctx), + getenv("KRB5_CONFIG")); if ((code = krb5_cc_resolve(ctx, cache_name ? cache_name : krb5_cc_default_name(ctx), &cc))) { goto out; } - if ((code = smb_krb5_parse_name(ctx, principal, &me))) { + if ((code = smb_krb5_parse_name(ctx, given_principal, &me))) { goto out; } @@ -195,6 +202,22 @@ int kerberos_kinit_password_ext(const char *principal, canon_princ = me; #endif /* MIT */ + code = smb_krb5_unparse_name(frame, + ctx, + canon_princ, + &canon_principal); + if (code != 0) { + goto out; + } + + DBG_DEBUG("%s mapped to %s\n", given_principal, canon_principal); + + canon_realm = smb_krb5_principal_get_realm(frame, ctx, canon_princ); + if (canon_realm == NULL) { + code = ENOMEM; + goto out; + } + if ((code = krb5_cc_initialize(ctx, cc, canon_princ))) { goto out; } @@ -210,6 +233,13 @@ int kerberos_kinit_password_ext(const char *principal, if (renew_till_time) { *renew_till_time = (time_t) my_creds.times.renew_till; } + + if (_canon_principal != NULL) { + *_canon_principal = talloc_move(mem_ctx, &canon_principal); + } + if (_canon_realm != NULL) { + *_canon_realm = talloc_move(mem_ctx, &canon_realm); + } out: if (ntstatus) { /* fast path */ @@ -239,6 +269,7 @@ int kerberos_kinit_password_ext(const char *principal, if (ctx) { krb5_free_context(ctx); } + TALLOC_FREE(frame); return code; } @@ -328,6 +359,9 @@ int kerberos_kinit_password(const char *principal, False, False, 0, + NULL, + NULL, + NULL, NULL); } diff --git a/source3/libads/kerberos_proto.h b/source3/libads/kerberos_proto.h index f92cabd757e..433bce9e0ec 100644 --- a/source3/libads/kerberos_proto.h +++ b/source3/libads/kerberos_proto.h @@ -45,7 +45,7 @@ struct PAC_DATA_CTR { /* The following definitions come from libads/kerberos.c */ -int kerberos_kinit_password_ext(const char *principal, +int kerberos_kinit_password_ext(const char *given_principal, const char *password, int time_offset, time_t *expire_time, @@ -54,6 +54,9 @@ int kerberos_kinit_password_ext(const char *principal, bool request_pac, bool add_netbios_addr, time_t renewable_time, + TALLOC_CTX *mem_ctx, + char **_canon_principal, + char **_canon_realm, NTSTATUS *ntstatus); int ads_kdestroy(const char *cc_name); diff --git a/source3/libads/kerberos_util.c b/source3/libads/kerberos_util.c index 68c0f302239..bfe53820aff 100644 --- a/source3/libads/kerberos_util.c +++ b/source3/libads/kerberos_util.c @@ -66,7 +66,8 @@ int ads_kinit_password(ADS_STRUCT *ads) ads->auth.time_offset, &ads->auth.tgt_expire, NULL, ads->auth.ccache_name, false, false, - ads->auth.renewable, NULL); + ads->auth.renewable, + NULL, NULL, NULL, NULL); if (ret) { DEBUG(0,("kerberos_kinit_password %s failed: %s\n", diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 6b4cd3591b0..4a0f59a1e80 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -3353,6 +3353,9 @@ static int net_ads_kerberos_kinit(struct net_context *c, int argc, const char ** true, true, 2592000, /* one month */ + NULL, + NULL, + NULL, &status); if (ret) { d_printf(_("failed to kinit password: %s\n"), diff --git a/source3/winbindd/winbindd_cred_cache.c b/source3/winbindd/winbindd_cred_cache.c index 85ad426446a..5baecf906b9 100644 --- a/source3/winbindd/winbindd_cred_cache.c +++ b/source3/winbindd/winbindd_cred_cache.c @@ -146,6 +146,9 @@ rekinit: False, /* no PAC required anymore */ True, WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, + NULL, + NULL, + NULL, NULL); gain_root_privilege(); @@ -343,6 +346,9 @@ static void krb5_ticket_gain_handler(struct tevent_context *event_ctx, False, /* no PAC required anymore */ True, WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, + NULL, + NULL, + NULL, NULL); gain_root_privilege(); -- 2.17.1 From 7ed225544705ad3b6f66122fe335bb8e47569d95 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 17 Sep 2019 10:08:10 +0200 Subject: [PATCH 208/376] s3:libsmb: avoid wrong debug message in cli_session_creds_prepare_krb5() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 361fb0efabfb189526c851107eee49161da2293c) --- source3/libsmb/cliconnect.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 3a116b6c7e6..7b6adfd6975 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -375,6 +375,8 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, /* * Ignore the error and hope that NTLM will work */ + TALLOC_FREE(frame); + return NT_STATUS_OK; } DBG_DEBUG("Successfully authenticated as %s to access %s using " -- 2.17.1 From 5628c4ffd328634014b5cc97f2717ff829bab8e3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 17 Sep 2019 08:49:13 +0200 Subject: [PATCH 209/376] s3:libsmb: let cli_session_creds_prepare_krb5() update the canonicalized principal to cli_credentials BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 6ed18c12c57efb2a010e0ce5196c51b48e57a4b9) --- source3/libsmb/cliconnect.c | 39 ++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 7b6adfd6975..94cec062881 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -229,6 +229,8 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, const char *user_account = NULL; const char *user_domain = NULL; const char *pass = NULL; + char *canon_principal = NULL; + char *canon_realm = NULL; const char *target_hostname = NULL; const DATA_BLOB *server_blob = NULL; bool got_kerberos_mechanism = false; @@ -237,6 +239,7 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, bool need_kinit = false; bool auth_requested = true; int ret; + bool ok; target_hostname = smbXcli_conn_remote_name(cli->conn); server_blob = smbXcli_conn_server_gss_blob(cli->conn); @@ -245,7 +248,6 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, if (server_blob != NULL && server_blob->length != 0) { char *OIDs[ASN1_MAX_OIDS] = { NULL, }; size_t i; - bool ok; /* * The server sent us the first part of the SPNEGO exchange in the @@ -354,9 +356,19 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, * only if required! */ setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1); - ret = kerberos_kinit_password(user_principal, pass, - 0 /* no time correction for now */, - NULL); + ret = kerberos_kinit_password_ext(user_principal, + pass, + 0, + 0, + 0, + NULL, + false, + false, + 0, + frame, + &canon_principal, + &canon_realm, + NULL); if (ret != 0) { int dbglvl = DBGLVL_NOTICE; @@ -379,9 +391,26 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, return NT_STATUS_OK; } - DBG_DEBUG("Successfully authenticated as %s to access %s using " + ok = cli_credentials_set_principal(creds, + canon_principal, + CRED_SPECIFIED); + if (!ok) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + ok = cli_credentials_set_realm(creds, + canon_realm, + CRED_SPECIFIED); + if (!ok) { + TALLOC_FREE(frame); + return NT_STATUS_NO_MEMORY; + } + + DBG_DEBUG("Successfully authenticated as %s (%s) to access %s using " "Kerberos\n", user_principal, + canon_principal, target_hostname); TALLOC_FREE(frame); -- 2.17.1 From 35e3f1a4054dd55e53e229fd78fe85433f577d95 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 13 Sep 2019 16:04:30 +0200 Subject: [PATCH 210/376] s3:libads/kerberos: always use the canonicalized principal after kinit We should always use krb5_get_init_creds_opt_set_canonicalize() and krb5_get_init_creds_opt_set_win2k() for heimdal and expect the client principal to be changed. There's no reason to have a different logic between MIT and Heimdal. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 0bced73bed481a8846a6b3e68be85941914390ba) --- source3/libads/kerberos.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 3e09d70268f..559ec3b7f53 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -167,7 +167,10 @@ int kerberos_kinit_password_ext(const char *given_principal, krb5_get_init_creds_opt_set_forwardable(opt, True); /* Turn on canonicalization for lower case realm support */ -#ifndef SAMBA4_USES_HEIMDAL /* MIT */ +#ifdef SAMBA4_USES_HEIMDAL + krb5_get_init_creds_opt_set_win2k(ctx, opt, true); + krb5_get_init_creds_opt_set_canonicalize(ctx, opt, true); +#else /* MIT */ krb5_get_init_creds_opt_set_canonicalize(opt, true); #endif /* MIT */ #if 0 @@ -196,11 +199,7 @@ int kerberos_kinit_password_ext(const char *given_principal, goto out; } -#ifndef SAMBA4_USES_HEIMDAL /* MIT */ canon_princ = my_creds.client; -#else - canon_princ = me; -#endif /* MIT */ code = smb_krb5_unparse_name(frame, ctx, -- 2.17.1 From d3d951f4240c543162976e18da9e0090254d72b6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 13 Sep 2019 16:04:30 +0200 Subject: [PATCH 211/376] krb5_wrap: smb_krb5_kinit_password_ccache() should always use the canonicalized principal We should always use krb5_get_init_creds_opt_set_canonicalize() and krb5_get_init_creds_opt_set_win2k() for heimdal and expect the client principal to be changed. There's no reason to have a different logic between MIT and Heimdal. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 5d0bf32ec0ad21d49587e3a1520ffdc8b5ae7614) --- lib/krb5_wrap/krb5_samba.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c index 72889fffcf0..55c17d481f4 100644 --- a/lib/krb5_wrap/krb5_samba.c +++ b/lib/krb5_wrap/krb5_samba.c @@ -2114,14 +2114,12 @@ krb5_error_code smb_krb5_kinit_password_ccache(krb5_context ctx, return code; } -#ifndef SAMBA4_USES_HEIMDAL /* MIT */ /* * We need to store the principal as returned from the KDC to the * credentials cache. If we don't do that the KRB5 library is not * able to find the tickets it is looking for */ principal = my_creds.client; -#endif code = krb5_cc_initialize(ctx, cc, principal); if (code) { goto done; -- 2.17.1 From 5d9961e64542ff1a7d360441db62ef6af3118292 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 13 Sep 2019 16:04:30 +0200 Subject: [PATCH 212/376] s4:auth: kinit_to_ccache() should always use the canonicalized principal We should always use krb5_get_init_creds_opt_set_canonicalize() and krb5_get_init_creds_opt_set_win2k() for heimdal and expect the client principal to be changed. There's no reason to have a different logic between MIT and Heimdal. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 162b4199493c1f179e775a325a19ae7a136c418b) --- source4/auth/kerberos/kerberos_util.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source4/auth/kerberos/kerberos_util.c b/source4/auth/kerberos/kerberos_util.c index 50bf8feec96..950d91f1737 100644 --- a/source4/auth/kerberos/kerberos_util.c +++ b/source4/auth/kerberos/kerberos_util.c @@ -313,6 +313,8 @@ done: */ krb5_get_init_creds_opt_set_win2k(smb_krb5_context->krb5_context, krb_options, true); + krb5_get_init_creds_opt_set_canonicalize(smb_krb5_context->krb5_context, + krb_options, true); #else /* MIT */ krb5_get_init_creds_opt_set_canonicalize(krb_options, true); #endif -- 2.17.1 From 2fd31d85701a4f05c306eb47791c65fd7e39d66d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 13 Sep 2019 16:04:30 +0200 Subject: [PATCH 213/376] s3:libads: ads_krb5_chg_password() should always use the canonicalized principal We should always use krb5_get_init_creds_opt_set_canonicalize() and krb5_get_init_creds_opt_set_win2k() for heimdal and expect the client principal to be changed. There's no reason to have a different logic between MIT and Heimdal. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 303b7e59a286896888ee2473995fc50bb2b5ce5e) --- source3/libads/krb5_setpw.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c index c3c9477c4cf..67bc2f4640d 100644 --- a/source3/libads/krb5_setpw.c +++ b/source3/libads/krb5_setpw.c @@ -203,6 +203,12 @@ static ADS_STATUS ads_krb5_chg_password(const char *kdc_host, krb5_get_init_creds_opt_set_renew_life(opts, 0); krb5_get_init_creds_opt_set_forwardable(opts, 0); krb5_get_init_creds_opt_set_proxiable(opts, 0); +#ifdef SAMBA4_USES_HEIMDAL + krb5_get_init_creds_opt_set_win2k(context, opts, true); + krb5_get_init_creds_opt_set_canonicalize(context, opts, true); +#else /* MIT */ + krb5_get_init_creds_opt_set_canonicalize(opts, true); +#endif /* MIT */ /* note that heimdal will fill in the local addresses if the addresses * in the creds_init_opt are all empty and then later fail with invalid -- 2.17.1 From 9de64feb1ec94ccef89931ce41ffebb18d80d921 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 13 Sep 2019 15:52:25 +0200 Subject: [PATCH 214/376] krb5_wrap: let smb_krb5_parse_name() accept enterprise principals BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 3bdf023956e861485be70430112ed38d0a5424f7) --- lib/krb5_wrap/krb5_samba.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c index 55c17d481f4..a4e73c64f00 100644 --- a/lib/krb5_wrap/krb5_samba.c +++ b/lib/krb5_wrap/krb5_samba.c @@ -701,6 +701,11 @@ krb5_error_code smb_krb5_parse_name(krb5_context context, } ret = krb5_parse_name(context, utf8_name, principal); + if (ret == KRB5_PARSE_MALFORMED) { + ret = krb5_parse_name_flags(context, utf8_name, + KRB5_PRINCIPAL_PARSE_ENTERPRISE, + principal); + } TALLOC_FREE(frame); return ret; } -- 2.17.1 From 82fb0291f1fe69143b093a4b3cb47fc36d964c22 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 11 Sep 2019 16:44:43 +0200 Subject: [PATCH 215/376] docs-xml: add "winbind use krb5 enterprise principals" option BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 9520652399696010c333a3ce7247809ce5337a91) --- .../winbindusekrb5enterpriseprincipals.xml | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 docs-xml/smbdotconf/winbind/winbindusekrb5enterpriseprincipals.xml diff --git a/docs-xml/smbdotconf/winbind/winbindusekrb5enterpriseprincipals.xml b/docs-xml/smbdotconf/winbind/winbindusekrb5enterpriseprincipals.xml new file mode 100644 index 00000000000..bfc11c8636c --- /dev/null +++ b/docs-xml/smbdotconf/winbind/winbindusekrb5enterpriseprincipals.xml @@ -0,0 +1,34 @@ + + + winbindd is able to get kerberos tickets for + pam_winbind with krb5_auth or wbinfo -K/--krb5auth=. + + + winbindd (at least on a domain member) is never be able + to have a complete picture of the trust topology (which is managed by the DCs). + There might be uPNSuffixes and msDS-SPNSuffixes values, + which don't belong to any AD domain at all. + + + With no + winbindd don't even get an incomplete picture of the topology. + + + It is not really required to know about the trust topology. + We can just rely on the [K]DCs of our primary domain (e.g. PRIMARY.A.EXAMPLE.COM) + and use enterprise principals e.g. upnfromB@B.EXAMPLE.COM@PRIMARY.A.EXAMPLE.COM + and follow the WRONG_REALM referrals in order to find the correct DC. + The final principal might be userfromB@INTERNALB.EXAMPLE.PRIVATE. + + + With yes + winbindd enterprise principals will be used. + + + +no +yes + -- 2.17.1 From e8c701673a8b0378e95f501c5ccb4f3cb661460e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 19 Jul 2019 15:10:09 +0000 Subject: [PATCH 216/376] s3:winbindd: implement the "winbind use krb5 enterprise principals" logic We can use enterprise principals (e.g. upnfromB@B.EXAMPLE.COM@PRIMARY.A.EXAMPLE.COM) and delegate the routing decisions to the KDCs. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit a77be15d28390c5d12202278adbe6b50200a2c1b) --- source3/winbindd/winbindd_pam.c | 57 +++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c index eaf16d0dced..c5b7c09b5c1 100644 --- a/source3/winbindd/winbindd_pam.c +++ b/source3/winbindd/winbindd_pam.c @@ -419,6 +419,15 @@ struct winbindd_domain *find_auth_domain(uint8_t flags, return find_domain_from_name_noinit(domain_name); } + if (lp_winbind_use_krb5_enterprise_principals()) { + /* + * If we use enterprise principals + * we always go trough our primary domain + * and follow the WRONG_REALM replies. + */ + flags &= ~WBFLAG_PAM_CONTACT_TRUSTDOM; + } + /* we can auth against trusted domains */ if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) { domain = find_domain_from_name_noinit(domain_name); @@ -723,7 +732,20 @@ static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx, return NT_STATUS_INVALID_PARAMETER; } - principal_s = talloc_asprintf(mem_ctx, "%s@%s", name_user, realm); + if (lp_winbind_use_krb5_enterprise_principals() && + name_namespace[0] != '\0') + { + principal_s = talloc_asprintf(mem_ctx, + "%s@%s@%s", + name_user, + name_namespace, + realm); + } else { + principal_s = talloc_asprintf(mem_ctx, + "%s@%s", + name_user, + realm); + } if (principal_s == NULL) { return NT_STATUS_NO_MEMORY; } @@ -1290,30 +1312,16 @@ static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain, /* what domain should we contact? */ - if ( IS_DC ) { - contact_domain = find_domain_from_name(name_namespace); - if (contact_domain == NULL) { - DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", - state->request->data.auth.user, name_domain, name_user, name_domain)); - result = NT_STATUS_NO_SUCH_USER; - goto done; - } - + if (lp_winbind_use_krb5_enterprise_principals()) { + contact_domain = find_auth_domain(0, name_namespace); } else { - if (is_myname(name_domain)) { - DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain)); - result = NT_STATUS_NO_SUCH_USER; - goto done; - } - contact_domain = find_domain_from_name(name_namespace); - if (contact_domain == NULL) { - DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", - state->request->data.auth.user, name_domain, name_user, name_domain)); - - result = NT_STATUS_NO_SUCH_USER; - goto done; - } + } + if (contact_domain == NULL) { + DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n", + state->request->data.auth.user, name_domain, name_user, name_namespace)); + result = NT_STATUS_NO_SUCH_USER; + goto done; } if (contact_domain->initialized && @@ -1326,7 +1334,8 @@ static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain, } if (!contact_domain->active_directory) { - DEBUG(3,("krb5 auth requested but domain is not Active Directory\n")); + DEBUG(3,("krb5 auth requested but domain (%s) is not Active Directory\n", + contact_domain->name)); return NT_STATUS_INVALID_LOGON_TYPE; } try_login: -- 2.17.1 From 5583d045a259a54f3f9000e747a713fa97effe15 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 18 Sep 2019 08:04:42 +0200 Subject: [PATCH 217/376] tests/pam_winbind.py: turn pypamtest.PamTestError into a failure A failure generated by the AssertionError() checks can be added to selftest/knownfail.d/*. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit cd3ffaabb568db26e0de5e83178487e5947c4f09) --- python/samba/tests/pam_winbind.py | 15 ++++++++++++--- python/samba/tests/pam_winbind_chauthtok.py | 5 ++++- python/samba/tests/pam_winbind_warn_pwd_expire.py | 5 ++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/python/samba/tests/pam_winbind.py b/python/samba/tests/pam_winbind.py index 68b05b30d7d..b05e8af6ffb 100644 --- a/python/samba/tests/pam_winbind.py +++ b/python/samba/tests/pam_winbind.py @@ -30,7 +30,10 @@ class SimplePamTests(samba.tests.TestCase): expected_rc = 0 # PAM_SUCCESS tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rc) - res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password]) + try: + res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password]) + except pypamtest.PamTestError as e: + raise AssertionError(str(e)) self.assertTrue(res is not None) @@ -42,7 +45,10 @@ class SimplePamTests(samba.tests.TestCase): expected_rc = 7 # PAM_AUTH_ERR tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rc) - res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password]) + try: + res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password]) + except pypamtest.PamTestError as e: + raise AssertionError(str(e)) self.assertTrue(res is not None) @@ -52,6 +58,9 @@ class SimplePamTests(samba.tests.TestCase): expected_rc = 0 # PAM_SUCCESS tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rc) - res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password]) + try: + res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password]) + except pypamtest.PamTestError as e: + raise AssertionError(str(e)) self.assertTrue(res is not None) diff --git a/python/samba/tests/pam_winbind_chauthtok.py b/python/samba/tests/pam_winbind_chauthtok.py index e5be3a83ce7..18c2705127a 100644 --- a/python/samba/tests/pam_winbind_chauthtok.py +++ b/python/samba/tests/pam_winbind_chauthtok.py @@ -31,6 +31,9 @@ class PamChauthtokTests(samba.tests.TestCase): expected_rc = 0 # PAM_SUCCESS tc = pypamtest.TestCase(pypamtest.PAMTEST_CHAUTHTOK, expected_rc) - res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password, newpassword, newpassword]) + try: + res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password, newpassword, newpassword]) + except pypamtest.PamTestError as e: + raise AssertionError(str(e)) self.assertTrue(res is not None) diff --git a/python/samba/tests/pam_winbind_warn_pwd_expire.py b/python/samba/tests/pam_winbind_warn_pwd_expire.py index df60bc5ace6..1af2f9befe1 100644 --- a/python/samba/tests/pam_winbind_warn_pwd_expire.py +++ b/python/samba/tests/pam_winbind_warn_pwd_expire.py @@ -31,7 +31,10 @@ class PasswordExpirePamTests(samba.tests.TestCase): expected_rc = 0 # PAM_SUCCESS tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rc) - res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password]) + try: + res = pypamtest.run_pamtest(unix_username, "samba", [tc], [password]) + except pypamtest.PamTestError as e: + raise AssertionError(str(e)) self.assertTrue(res is not None) if warn_pwd_expire == 0: -- 2.17.1 From 913c79d2e06acf93b7a3fedab6b0c30a0c1272bf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 20 Sep 2019 08:13:28 +0200 Subject: [PATCH 218/376] tests/pam_winbind.py: allow upn names to be used in USERNAME with an empty DOMAIN value BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 653e90485854d978dc522e689cd78c19dcc22a70) --- python/samba/tests/pam_winbind.py | 10 ++++++++-- python/samba/tests/pam_winbind_chauthtok.py | 5 ++++- python/samba/tests/pam_winbind_warn_pwd_expire.py | 5 ++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/python/samba/tests/pam_winbind.py b/python/samba/tests/pam_winbind.py index b05e8af6ffb..708f408f768 100644 --- a/python/samba/tests/pam_winbind.py +++ b/python/samba/tests/pam_winbind.py @@ -26,7 +26,10 @@ class SimplePamTests(samba.tests.TestCase): domain = os.environ["DOMAIN"] username = os.environ["USERNAME"] password = os.environ["PASSWORD"] - unix_username = "%s/%s" % (domain, username) + if domain != "": + unix_username = "%s/%s" % (domain, username) + else: + unix_username = "%s" % username expected_rc = 0 # PAM_SUCCESS tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rc) @@ -41,7 +44,10 @@ class SimplePamTests(samba.tests.TestCase): domain = os.environ["DOMAIN"] username = os.environ["USERNAME"] password = "WrongPassword" - unix_username = "%s/%s" % (domain, username) + if domain != "": + unix_username = "%s/%s" % (domain, username) + else: + unix_username = "%s" % username expected_rc = 7 # PAM_AUTH_ERR tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rc) diff --git a/python/samba/tests/pam_winbind_chauthtok.py b/python/samba/tests/pam_winbind_chauthtok.py index 18c2705127a..c1d569b3cd0 100644 --- a/python/samba/tests/pam_winbind_chauthtok.py +++ b/python/samba/tests/pam_winbind_chauthtok.py @@ -27,7 +27,10 @@ class PamChauthtokTests(samba.tests.TestCase): username = os.environ["USERNAME"] password = os.environ["PASSWORD"] newpassword = os.environ["NEWPASSWORD"] - unix_username = "%s/%s" % (domain, username) + if domain != "": + unix_username = "%s/%s" % (domain, username) + else: + unix_username = "%s" % username expected_rc = 0 # PAM_SUCCESS tc = pypamtest.TestCase(pypamtest.PAMTEST_CHAUTHTOK, expected_rc) diff --git a/python/samba/tests/pam_winbind_warn_pwd_expire.py b/python/samba/tests/pam_winbind_warn_pwd_expire.py index 1af2f9befe1..56f5da94f98 100644 --- a/python/samba/tests/pam_winbind_warn_pwd_expire.py +++ b/python/samba/tests/pam_winbind_warn_pwd_expire.py @@ -27,7 +27,10 @@ class PasswordExpirePamTests(samba.tests.TestCase): username = os.environ["USERNAME"] password = os.environ["PASSWORD"] warn_pwd_expire = int(os.environ["WARN_PWD_EXPIRE"]) - unix_username = "%s/%s" % (domain, username) + if domain != "": + unix_username = "%s/%s" % (domain, username) + else: + unix_username = "%s" % username expected_rc = 0 # PAM_SUCCESS tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rc) -- 2.17.1 From 8aae6dd753b51bc54042c8cbc9308e08cdeef089 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 18 Sep 2019 01:25:58 +0200 Subject: [PATCH 219/376] test_pam_winbind.sh: allow different pam_winbindd config options to be specified BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 3d38a8e9135bb72bc4ca079fab0eb5358942b3f1) --- python/samba/tests/test_pam_winbind.sh | 12 +++++++---- .../samba/tests/test_pam_winbind_chauthtok.sh | 4 ++-- .../tests/test_pam_winbind_warn_pwd_expire.sh | 20 +++++++++++-------- selftest/tests.py | 6 +++--- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/python/samba/tests/test_pam_winbind.sh b/python/samba/tests/test_pam_winbind.sh index 0406b108b31..755e67280fa 100755 --- a/python/samba/tests/test_pam_winbind.sh +++ b/python/samba/tests/test_pam_winbind.sh @@ -12,6 +12,10 @@ PASSWORD="$3" export PASSWORD shift 3 +PAM_OPTIONS="$1" +export PAM_OPTIONS +shift 1 + PAM_WRAPPER_PATH="$BINDIR/default/third_party/pam_wrapper" pam_winbind="$BINDIR/shared/pam_winbind.so" @@ -19,10 +23,10 @@ service_dir="$SELFTEST_TMPDIR/pam_services" service_file="$service_dir/samba" mkdir $service_dir -echo "auth required $pam_winbind debug debug_state" > $service_file -echo "account required $pam_winbind debug debug_state" >> $service_file -echo "password required $pam_winbind debug debug_state" >> $service_file -echo "session required $pam_winbind debug debug_state" >> $service_file +echo "auth required $pam_winbind debug debug_state $PAM_OPTIONS" > $service_file +echo "account required $pam_winbind debug debug_state $PAM_OPTIONS" >> $service_file +echo "password required $pam_winbind debug debug_state $PAM_OPTIONS" >> $service_file +echo "session required $pam_winbind debug debug_state $PAM_OPTIONS" >> $service_file PAM_WRAPPER="1" export PAM_WRAPPER diff --git a/python/samba/tests/test_pam_winbind_chauthtok.sh b/python/samba/tests/test_pam_winbind_chauthtok.sh index 5887699300a..48adc81859d 100755 --- a/python/samba/tests/test_pam_winbind_chauthtok.sh +++ b/python/samba/tests/test_pam_winbind_chauthtok.sh @@ -53,11 +53,11 @@ PAM_WRAPPER_DEBUGLEVEL=${PAM_WRAPPER_DEBUGLEVEL:="2"} export PAM_WRAPPER_DEBUGLEVEL case $PAM_OPTIONS in - use_authtok) + *use_authtok*) PAM_AUTHTOK="$NEWPASSWORD" export PAM_AUTHTOK ;; - try_authtok) + *try_authtok*) PAM_AUTHTOK="$NEWPASSWORD" export PAM_AUTHTOK ;; diff --git a/python/samba/tests/test_pam_winbind_warn_pwd_expire.sh b/python/samba/tests/test_pam_winbind_warn_pwd_expire.sh index 16dede44227..348d2ae8387 100755 --- a/python/samba/tests/test_pam_winbind_warn_pwd_expire.sh +++ b/python/samba/tests/test_pam_winbind_warn_pwd_expire.sh @@ -12,6 +12,10 @@ PASSWORD="$3" export PASSWORD shift 3 +PAM_OPTIONS="$1" +export PAM_OPTIONS +shift 1 + PAM_WRAPPER_PATH="$BINDIR/default/third_party/pam_wrapper" pam_winbind="$BINDIR/shared/pam_winbind.so" @@ -37,10 +41,10 @@ export PAM_WRAPPER_DEBUGLEVEL WARN_PWD_EXPIRE="50" export WARN_PWD_EXPIRE -echo "auth required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE" > $service_file -echo "account required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE" >> $service_file -echo "password required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE" >> $service_file -echo "session required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE" >> $service_file +echo "auth required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE $PAM_OPTIONS" > $service_file +echo "account required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE $PAM_OPTIONS" >> $service_file +echo "password required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE $PAM_OPTIONS" >> $service_file +echo "session required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE $PAM_OPTIONS" >> $service_file PYTHONPATH="$PYTHONPATH:$PAM_WRAPPER_PATH:$(dirname $0)" $PYTHON -m samba.subunit.run samba.tests.pam_winbind_warn_pwd_expire exit_code=$? @@ -54,10 +58,10 @@ fi WARN_PWD_EXPIRE="0" export WARN_PWD_EXPIRE -echo "auth required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE" > $service_file -echo "account required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE" >> $service_file -echo "password required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE" >> $service_file -echo "session required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE" >> $service_file +echo "auth required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE $PAM_OPTIONS" > $service_file +echo "account required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE $PAM_OPTIONS" >> $service_file +echo "password required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE $PAM_OPTIONS" >> $service_file +echo "session required $pam_winbind debug debug_state warn_pwd_expire=$WARN_PWD_EXPIRE $PAM_OPTIONS" >> $service_file PYTHONPATH="$PYTHONPATH:$PAM_WRAPPER_PATH:$(dirname $0)" $PYTHON -m samba.subunit.run samba.tests.pam_winbind_warn_pwd_expire exit_code=$? diff --git a/selftest/tests.py b/selftest/tests.py index 1568f29b212..2d3587837a3 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -216,11 +216,11 @@ if with_pam: plantestsuite("samba.tests.pam_winbind(local)", "ad_member", [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), valgrindify(python), pam_wrapper_so_path, - "$SERVER", "$USERNAME", "$PASSWORD"]) + "$SERVER", "$USERNAME", "$PASSWORD", "''"]) plantestsuite("samba.tests.pam_winbind(domain)", "ad_member", [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), valgrindify(python), pam_wrapper_so_path, - "$DOMAIN", "$DC_USERNAME", "$DC_PASSWORD"]) + "$DOMAIN", "$DC_USERNAME", "$DC_PASSWORD", "''"]) for pam_options in ["''", "use_authtok", "try_authtok"]: plantestsuite("samba.tests.pam_winbind_chauthtok with options %s" % pam_options, "ad_member", @@ -233,7 +233,7 @@ if with_pam: plantestsuite("samba.tests.pam_winbind_warn_pwd_expire(domain)", "ad_member", [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind_warn_pwd_expire.sh"), valgrindify(python), pam_wrapper_so_path, - "$DOMAIN", "alice", "Secret007"]) + "$DOMAIN", "alice", "Secret007", "''"]) plantestsuite("samba.unittests.krb5samba", "none", -- 2.17.1 From cfee90317203e174c4553c264f47387afef7aeaa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 18 Sep 2019 01:25:23 +0200 Subject: [PATCH 220/376] selftest/tests.py: prepare looping over pam_winbindd tests BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 72daf99fd1ffd8269fce25d69458de35e2ae32cc) --- selftest/tests.py | 58 ++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/selftest/tests.py b/selftest/tests.py index 2d3587837a3..95d027f9521 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -213,27 +213,43 @@ planpythontestsuite("none", "samba.tests.tdb_util") planpythontestsuite("none", "samba.tests.samdb_api") if with_pam: - plantestsuite("samba.tests.pam_winbind(local)", "ad_member", - [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), - valgrindify(python), pam_wrapper_so_path, - "$SERVER", "$USERNAME", "$PASSWORD", "''"]) - plantestsuite("samba.tests.pam_winbind(domain)", "ad_member", - [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), - valgrindify(python), pam_wrapper_so_path, - "$DOMAIN", "$DC_USERNAME", "$DC_PASSWORD", "''"]) - - for pam_options in ["''", "use_authtok", "try_authtok"]: - plantestsuite("samba.tests.pam_winbind_chauthtok with options %s" % pam_options, "ad_member", - [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind_chauthtok.sh"), - valgrindify(python), pam_wrapper_so_path, pam_set_items_so_path, - "$DOMAIN", "TestPamOptionsUser", "oldp@ssword0", "newp@ssword0", - pam_options, 'yes', - "$DC_SERVER", "$DC_USERNAME", "$DC_PASSWORD"]) - - plantestsuite("samba.tests.pam_winbind_warn_pwd_expire(domain)", "ad_member", - [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind_warn_pwd_expire.sh"), - valgrindify(python), pam_wrapper_so_path, - "$DOMAIN", "alice", "Secret007", "''"]) + env = "ad_member" + options = [ + { + "description": "default", + "pam_options": "", + }, + ] + for o in options: + description = o["description"] + pam_options = "'%s'" % o["pam_options"] + + plantestsuite("samba.tests.pam_winbind(local+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$SERVER", "$USERNAME", "$PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(domain+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$DOMAIN", "$DC_USERNAME", "$DC_PASSWORD", + pam_options]) + + for authtok_options in ["", "use_authtok", "try_authtok"]: + _pam_options = "'%s %s'" % (o["pam_options"], authtok_options) + _description = "%s %s" % (description, authtok_options) + plantestsuite("samba.tests.pam_winbind_chauthtok(domain+%s)" % _description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind_chauthtok.sh"), + valgrindify(python), pam_wrapper_so_path, pam_set_items_so_path, + "$DOMAIN", "TestPamOptionsUser", "oldp@ssword0", "newp@ssword0", + _pam_options, 'yes', + "$DC_SERVER", "$DC_USERNAME", "$DC_PASSWORD"]) + + plantestsuite("samba.tests.pam_winbind_warn_pwd_expire(domain+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind_warn_pwd_expire.sh"), + valgrindify(python), pam_wrapper_so_path, + "$DOMAIN", "alice", "Secret007", + pam_options]) plantestsuite("samba.unittests.krb5samba", "none", -- 2.17.1 From e7b84754510b5850891752c5fc943714f0a46a4d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 18 Sep 2019 08:08:57 +0200 Subject: [PATCH 221/376] selftest/tests.py: test pam_winbind with krb5_auth BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 36e95e42ea8a7e5a4091a647215d06d2ab47fab6) --- selftest/tests.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/selftest/tests.py b/selftest/tests.py index 95d027f9521..0bcb826071c 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -215,6 +215,10 @@ planpythontestsuite("none", "samba.tests.samdb_api") if with_pam: env = "ad_member" options = [ + { + "description": "krb5", + "pam_options": "krb5_auth krb5_ccache_type=FILE", + }, { "description": "default", "pam_options": "", -- 2.17.1 From 2290dfe49bf267784d3bec491cb9b8978c3d66dc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 18 Sep 2019 14:03:34 +0200 Subject: [PATCH 222/376] selftest/tests.py: test pam_winbind with a lot of username variations BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit f07b542c61f84a97c097208e10bf9375ddfa9a15) --- selftest/tests.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/selftest/tests.py b/selftest/tests.py index 0bcb826071c..e37cb9e7b96 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -233,11 +233,36 @@ if with_pam: valgrindify(python), pam_wrapper_so_path, "$SERVER", "$USERNAME", "$PASSWORD", pam_options]) - plantestsuite("samba.tests.pam_winbind(domain+%s)" % description, env, + plantestsuite("samba.tests.pam_winbind(domain1+%s)" % description, env, [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), valgrindify(python), pam_wrapper_so_path, "$DOMAIN", "$DC_USERNAME", "$DC_PASSWORD", pam_options]) + plantestsuite("samba.tests.pam_winbind(domain2+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$REALM", "$DC_USERNAME", "$DC_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(domain3+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "''", "${DC_USERNAME}@${DOMAIN}", "$DC_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(domain4+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "''", "${DC_USERNAME}@${REALM}", "$DC_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(domain5+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$REALM", "${DC_USERNAME}@${DOMAIN}", "$DC_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(domain6+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$DOMAIN", "${DC_USERNAME}@${REALM}", "$DC_PASSWORD", + pam_options]) for authtok_options in ["", "use_authtok", "try_authtok"]: _pam_options = "'%s %s'" % (o["pam_options"], authtok_options) -- 2.17.1 From e3760d6e3a3d141719e47eed755805a330609cac Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 20 Mar 2017 11:39:41 +0100 Subject: [PATCH 223/376] selftest: Export TRUST information in the ad_member target environment BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Andreas Schneider Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit 13e3811c9510cf213881527877bed40092e0b33c) --- selftest/target/Samba.pm | 22 ++++++++++++++++++++++ selftest/target/Samba3.pm | 24 ++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/selftest/target/Samba.pm b/selftest/target/Samba.pm index ca3099c9d05..c30f6fe33ce 100644 --- a/selftest/target/Samba.pm +++ b/selftest/target/Samba.pm @@ -724,6 +724,28 @@ my @exported_envvars = ( "TRUST_REALM", "TRUST_DOMSID", + # stuff related to a trusted domain, on a trust_member + # the domain behind a forest trust (two-way) + "TRUST_F_BOTH_SERVER", + "TRUST_F_BOTH_SERVER_IP", + "TRUST_F_BOTH_SERVER_IPV6", + "TRUST_F_BOTH_NETBIOSNAME", + "TRUST_F_BOTH_USERNAME", + "TRUST_F_BOTH_PASSWORD", + "TRUST_F_BOTH_DOMAIN", + "TRUST_F_BOTH_REALM", + + # stuff related to a trusted domain, on a trust_member + # the domain behind an external trust (two-way) + "TRUST_E_BOTH_SERVER", + "TRUST_E_BOTH_SERVER_IP", + "TRUST_E_BOTH_SERVER_IPV6", + "TRUST_E_BOTH_NETBIOSNAME", + "TRUST_E_BOTH_USERNAME", + "TRUST_E_BOTH_PASSWORD", + "TRUST_E_BOTH_DOMAIN", + "TRUST_E_BOTH_REALM", + # domain controller stuff "DC_SERVER", "DC_SERVER_IP", diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 131d576a767..52d78ea51c0 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -181,7 +181,7 @@ sub check_env($$) nt4_member => ["nt4_dc"], - ad_member => ["ad_dc"], + ad_member => ["ad_dc", "fl2008r2dc", "fl2003dc"], ad_member_rfc2307 => ["ad_dc_ntvfs"], ad_member_idmap_rid => ["ad_dc"], ad_member_idmap_ad => ["fl2008r2dc"], @@ -369,7 +369,7 @@ sub setup_nt4_member sub setup_ad_member { - my ($self, $prefix, $dcvars) = @_; + my ($self, $prefix, $dcvars, $trustvars_f, $trustvars_e) = @_; my $prefix_abs = abs_path($prefix); my @dirs = (); @@ -493,6 +493,26 @@ sub setup_ad_member $ret->{DC_USERNAME} = $dcvars->{USERNAME}; $ret->{DC_PASSWORD} = $dcvars->{PASSWORD}; + # forest trust + $ret->{TRUST_F_BOTH_SERVER} = $trustvars_f->{SERVER}; + $ret->{TRUST_F_BOTH_SERVER_IP} = $trustvars_f->{SERVER_IP}; + $ret->{TRUST_F_BOTH_SERVER_IPV6} = $trustvars_f->{SERVER_IPV6}; + $ret->{TRUST_F_BOTH_NETBIOSNAME} = $trustvars_f->{NETBIOSNAME}; + $ret->{TRUST_F_BOTH_USERNAME} = $trustvars_f->{USERNAME}; + $ret->{TRUST_F_BOTH_PASSWORD} = $trustvars_f->{PASSWORD}; + $ret->{TRUST_F_BOTH_DOMAIN} = $trustvars_f->{DOMAIN}; + $ret->{TRUST_F_BOTH_REALM} = $trustvars_f->{REALM}; + + # external trust + $ret->{TRUST_E_BOTH_SERVER} = $trustvars_e->{SERVER}; + $ret->{TRUST_E_BOTH_SERVER_IP} = $trustvars_e->{SERVER_IP}; + $ret->{TRUST_E_BOTH_SERVER_IPV6} = $trustvars_e->{SERVER_IPV6}; + $ret->{TRUST_E_BOTH_NETBIOSNAME} = $trustvars_e->{NETBIOSNAME}; + $ret->{TRUST_E_BOTH_USERNAME} = $trustvars_e->{USERNAME}; + $ret->{TRUST_E_BOTH_PASSWORD} = $trustvars_e->{PASSWORD}; + $ret->{TRUST_E_BOTH_DOMAIN} = $trustvars_e->{DOMAIN}; + $ret->{TRUST_E_BOTH_REALM} = $trustvars_e->{REALM}; + return $ret; } -- 2.17.1 From f0f2ce68e450dbf9f8f7e2257dee9e5e00c29567 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 10 Jun 2017 14:38:40 +0200 Subject: [PATCH 224/376] selftest/tests.py: test pam_winbind for trusts domains BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit ad6f0e056ac27ab5c078dbdbff44372da05caab2) --- selftest/tests.py | 84 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/selftest/tests.py b/selftest/tests.py index e37cb9e7b96..e767f276353 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -263,6 +263,90 @@ if with_pam: valgrindify(python), pam_wrapper_so_path, "$DOMAIN", "${DC_USERNAME}@${REALM}", "$DC_PASSWORD", pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_f_both1+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$TRUST_F_BOTH_DOMAIN", + "$TRUST_F_BOTH_USERNAME", + "$TRUST_F_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_f_both2+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$TRUST_F_BOTH_REALM", + "$TRUST_F_BOTH_USERNAME", + "$TRUST_F_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_f_both3+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "''", + "${TRUST_F_BOTH_USERNAME}@${TRUST_F_BOTH_DOMAIN}", + "$TRUST_F_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_f_both4+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "''", + "${TRUST_F_BOTH_USERNAME}@${TRUST_F_BOTH_REALM}", + "$TRUST_F_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_f_both5+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "${TRUST_F_BOTH_REALM}", + "${TRUST_F_BOTH_USERNAME}@${TRUST_F_BOTH_DOMAIN}", + "$TRUST_F_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_f_both6+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "${TRUST_F_BOTH_DOMAIN}", + "${TRUST_F_BOTH_USERNAME}@${TRUST_F_BOTH_REALM}", + "$TRUST_F_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_e_both1+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$TRUST_E_BOTH_DOMAIN", + "$TRUST_E_BOTH_USERNAME", + "$TRUST_E_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_e_both2+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "$TRUST_E_BOTH_REALM", + "$TRUST_E_BOTH_USERNAME", + "$TRUST_E_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_e_both3+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "''", + "${TRUST_E_BOTH_USERNAME}@${TRUST_E_BOTH_DOMAIN}", + "$TRUST_E_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_e_both4+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "''", + "${TRUST_E_BOTH_USERNAME}@${TRUST_E_BOTH_REALM}", + "$TRUST_E_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_e_both5+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "${TRUST_E_BOTH_REALM}", + "${TRUST_E_BOTH_USERNAME}@${TRUST_E_BOTH_DOMAIN}", + "$TRUST_E_BOTH_PASSWORD", + pam_options]) + plantestsuite("samba.tests.pam_winbind(trust_e_both6+%s)" % description, env, + [os.path.join(srcdir(), "python/samba/tests/test_pam_winbind.sh"), + valgrindify(python), pam_wrapper_so_path, + "${TRUST_E_BOTH_DOMAIN}", + "${TRUST_E_BOTH_USERNAME}@${TRUST_E_BOTH_REALM}", + "$TRUST_E_BOTH_PASSWORD", + pam_options]) for authtok_options in ["", "use_authtok", "try_authtok"]: _pam_options = "'%s %s'" % (o["pam_options"], authtok_options) -- 2.17.1 From f836385629c097ec8564ac19045c5906fdb13f64 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 18 Sep 2019 08:02:38 +0200 Subject: [PATCH 225/376] selftest/Samba3.pm: use "winbind scan trusted domains = no" for ad_member This demonstrates that we rely on knowning about trusted domains before we can do krb5_auth in winbindd. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner (cherry picked from commit e2737a74d4453a3d65e5466ddc4405d68444df27) --- selftest/knownfail.d/pam_winbind_krb5 | 1 + selftest/target/Samba3.pm | 1 + 2 files changed, 2 insertions(+) create mode 100644 selftest/knownfail.d/pam_winbind_krb5 diff --git a/selftest/knownfail.d/pam_winbind_krb5 b/selftest/knownfail.d/pam_winbind_krb5 new file mode 100644 index 00000000000..1dd0c7d3f1c --- /dev/null +++ b/selftest/knownfail.d/pam_winbind_krb5 @@ -0,0 +1 @@ +^samba.tests.pam_winbind.trust_._both..krb5..samba.tests.pam_winbind.SimplePamTests.test_authenticate diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 52d78ea51c0..a75ec094b5e 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -416,6 +416,7 @@ sub setup_ad_member template homedir = /home/%D/%G/%U auth event notification = true password server = $dcvars->{SERVER} + winbind scan trusted domains = no [sub_dug] path = $share_dir/D_%D/U_%U/G_%G -- 2.17.1 From fcb247f41478e8b1f8ff504e901cefc047bdf197 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 18 Sep 2019 08:10:26 +0200 Subject: [PATCH 226/376] selftest/Samba3.pm: use "winbind use krb5 enterprise principals = yes" for ad_member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This demonstrates that can do krb5_auth in winbindd without knowning about trusted domains. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14124 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner Autobuild-User(master): Günther Deschner Autobuild-Date(master): Tue Sep 24 19:51:29 UTC 2019 on sn-devel-184 (cherry picked from commit 0ee085b594878f5e0e83839f465303754f015459) --- selftest/knownfail.d/pam_winbind_krb5 | 1 - selftest/target/Samba3.pm | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 selftest/knownfail.d/pam_winbind_krb5 diff --git a/selftest/knownfail.d/pam_winbind_krb5 b/selftest/knownfail.d/pam_winbind_krb5 deleted file mode 100644 index 1dd0c7d3f1c..00000000000 --- a/selftest/knownfail.d/pam_winbind_krb5 +++ /dev/null @@ -1 +0,0 @@ -^samba.tests.pam_winbind.trust_._both..krb5..samba.tests.pam_winbind.SimplePamTests.test_authenticate diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index a75ec094b5e..32bd8698df2 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -417,6 +417,7 @@ sub setup_ad_member auth event notification = true password server = $dcvars->{SERVER} winbind scan trusted domains = no + winbind use krb5 enterprise principals = yes [sub_dug] path = $share_dir/D_%D/U_%U/G_%G -- 2.17.1 From 75702977dde834f06460e8434ea98b81020efbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= Date: Mon, 23 Sep 2019 08:57:33 +0200 Subject: [PATCH 227/376] fault.c: improve fault_report message text pointing to our wiki BUG: https://bugzilla.samba.org/show_bug.cgi?id=14139 Signed-off-by: Bjoern Jacke Reviewed-by: Alexander Bokovoy (cherry picked from commit ec4c5975528f3d3ab9c8813e176c6d1a2f1ca506) --- lib/util/fault.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/util/fault.c b/lib/util/fault.c index 5be9162679e..c42bc51789a 100644 --- a/lib/util/fault.c +++ b/lib/util/fault.c @@ -78,7 +78,11 @@ static void fault_report(int sig) DEBUGSEP(0); DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),SAMBA_VERSION_STRING)); - DEBUG(0,("\nPlease read the Trouble-Shooting section of the Samba HOWTO\n")); + DEBUG(0,("\nIf you are running a recent Samba version, and " + "if you think this problem is not yet fixed in the " + "latest versions, please consider reporting this " + "bug, see " + "https://wiki.samba.org/index.php/Bug_Reporting\n")); DEBUGSEP(0); smb_panic("internal error"); -- 2.17.1 From a89e8588449a09f47250e81d87828de74d4c5106 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Thu, 12 Sep 2019 16:39:10 +0200 Subject: [PATCH 228/376] s3-winbindd: fix forest trusts with additional trust attributes. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14130 Guenther Signed-off-by: Guenther Deschner Reviewed-by: Stefan Metzmacher Reviewed-by: Andreas Schneider (cherry picked from commit d78c87e665e23e6470a19a69383ede7137172c26) --- source3/winbindd/winbindd_ads.c | 2 +- source3/winbindd/winbindd_util.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index 5f20cfb7f76..485ca831be9 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -1457,7 +1457,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, */ if ((trust->trust_attributes - == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) && + & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) && !domain->primary ) { DEBUG(10,("trusted_domains: Skipping external trusted " diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index cc4c3f7391a..ee7651c9639 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -723,7 +723,7 @@ static void rescan_forest_trusts( void ) if ( (flags & NETR_TRUST_FLAG_INBOUND) && (type == LSA_TRUST_TYPE_UPLEVEL) && - (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) ) + (attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) ) { /* add the trusted domain if we don't know about it */ -- 2.17.1 From 4709a848c550e6b56a8a94ca722fa6ab091e3725 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 23 Sep 2019 15:18:55 +0200 Subject: [PATCH 229/376] s3:waf: Do not check for nanosleep() as we don't use it anywhere MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use usleep() in the meantime. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Pair-Programmed-With: Isaac Boukris Reviewed-by: Matthias Dieter Wallnöfer Reviewed-by: Alexander Bokovoy (cherry picked from commit 952e1812fa9bdc1bac2a7ae5ebb5532f1ea31447) --- source3/wscript | 1 - 1 file changed, 1 deletion(-) diff --git a/source3/wscript b/source3/wscript index 4a3e75605e7..7b257bcb845 100644 --- a/source3/wscript +++ b/source3/wscript @@ -116,7 +116,6 @@ def configure(conf): conf.CHECK_FUNCS('fstatat') conf.CHECK_FUNCS('getpwent_r setenv clearenv strcasecmp fcvt fcvtl') conf.CHECK_FUNCS('syslog vsyslog timegm setlocale') - conf.CHECK_FUNCS_IN('nanosleep', 'rt') conf.CHECK_FUNCS('lutimes futimes utimensat futimens') conf.CHECK_FUNCS('mlock munlock mlockall munlockall') conf.CHECK_FUNCS('memalign posix_memalign hstrerror') -- 2.17.1 From 7ec980b991fd5b62e5739a5fdb2dcbb1306c52d9 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 23 Sep 2019 15:14:24 +0200 Subject: [PATCH 230/376] replace: Only link against librt if really needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fdatasync() and clock_gettime() are provided by glibc on Linux, so there is no need to link against librt. Checks have been added so if there are platforms which require it are still functional. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Pair-Programmed-With: Isaac Boukris Reviewed-by: Matthias Dieter Wallnöfer Reviewed-by: Alexander Bokovoy (cherry picked from commit 480152dd6729d4c58faca6f3e4fa91ff4614c272) --- lib/replace/wscript | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/replace/wscript b/lib/replace/wscript index 4df1b4d77c4..ec5e085a350 100644 --- a/lib/replace/wscript +++ b/lib/replace/wscript @@ -458,11 +458,28 @@ def configure(conf): conf.CHECK_C_PROTOTYPE('dlopen', 'void *dlopen(const char* filename, unsigned int flags)', define='DLOPEN_TAKES_UNSIGNED_FLAGS', headers='dlfcn.h dl.h') - if conf.CHECK_FUNCS_IN('fdatasync', 'rt', checklibc=True): + # + # Check for clock_gettime and fdatasync + # + # First check libc to avoid linking libreplace against librt. + # + if conf.CHECK_FUNCS('fdatasync'): # some systems are missing the declaration conf.CHECK_DECLS('fdatasync') + else: + if conf.CHECK_FUNCS_IN('fdatasync', 'rt'): + # some systems are missing the declaration + conf.CHECK_DECLS('fdatasync') + + has_clock_gettime = False + if conf.CHECK_FUNCS('clock_gettime'): + has_clock_gettime = True + + if not has_clock_gettime: + if conf.CHECK_FUNCS_IN('clock_gettime', 'rt', checklibc=True): + has_clock_gettime = True - if conf.CHECK_FUNCS_IN('clock_gettime', 'rt', checklibc=True): + if has_clock_gettime: for c in ['CLOCK_MONOTONIC', 'CLOCK_PROCESS_CPUTIME_ID', 'CLOCK_REALTIME']: conf.CHECK_CODE(''' #if TIME_WITH_SYS_TIME @@ -816,6 +833,7 @@ def build(bld): extra_libs = '' if bld.CONFIG_SET('HAVE_LIBBSD'): extra_libs += ' bsd' + if bld.CONFIG_SET('HAVE_LIBRT'): extra_libs += ' rt' bld.SAMBA_SUBSYSTEM('LIBREPLACE_HOSTCC', REPLACE_HOSTCC_SOURCE, @@ -856,7 +874,7 @@ def build(bld): # at the moment: # hide_symbols=bld.BUILTIN_LIBRARY('replace'), private_library=True, - deps='crypt dl nsl socket rt attr' + extra_libs) + deps='crypt dl nsl socket attr' + extra_libs) replace_test_cflags = '' if bld.CONFIG_SET('HAVE_WNO_FORMAT_TRUNCATION'): -- 2.17.1 From 82c9a6c4b0adfc472b342c898c2cb3b382132c53 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 23 Sep 2019 16:10:35 +0200 Subject: [PATCH 231/376] pthreadpool: Only link pthreadpool against librt if we have to MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This calls clock_gettime() which is available in glibc on Linux. If the wscript in libreplace detected that librt is needed for clock_gettime() we have to link against it. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Pair-Programmed-With: Isaac Boukris Reviewed-by: Matthias Dieter Wallnöfer Reviewed-by: Alexander Bokovoy (cherry picked from commit 4b28239d13b17e42eb5aa4b405342f46347f3de4) --- lib/pthreadpool/wscript_build | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/pthreadpool/wscript_build b/lib/pthreadpool/wscript_build index 57df25548b1..70aa7cbf041 100644 --- a/lib/pthreadpool/wscript_build +++ b/lib/pthreadpool/wscript_build @@ -1,12 +1,17 @@ #!/usr/bin/env python if bld.env.WITH_PTHREADPOOL: + extra_libs='' + + # Link to librt if needed for clock_gettime() + if bld.CONFIG_SET('HAVE_LIBRT'): extra_libs += ' rt' + bld.SAMBA_SUBSYSTEM('PTHREADPOOL', source='''pthreadpool.c pthreadpool_pipe.c pthreadpool_tevent.c ''', - deps='pthread rt replace tevent-util') + deps='pthread replace tevent-util' + extra_libs) else: bld.SAMBA_SUBSYSTEM('PTHREADPOOL', source='''pthreadpool_sync.c -- 2.17.1 From 62f0ce14a1b8e03e4c4fd8710df86a9a58bca73b Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 23 Sep 2019 17:04:57 +0200 Subject: [PATCH 232/376] third_party: Only link cmocka against librt if really needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cmocka also uses clock_gettime(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Pair-Programmed-With: Isaac Boukris Reviewed-by: Matthias Dieter Wallnöfer Reviewed-by: Alexander Bokovoy (cherry picked from commit 36e8d715bc8dc1e8466f5a5c9798df76310b7572) --- third_party/cmocka/wscript | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/third_party/cmocka/wscript b/third_party/cmocka/wscript index 9ebdd7cfbe9..3c2ad50801a 100644 --- a/third_party/cmocka/wscript +++ b/third_party/cmocka/wscript @@ -12,8 +12,13 @@ def build(bld): if bld.CONFIG_SET('USING_SYSTEM_CMOCKA'): return + extra_libs='' + + # Link to librt if needed for clock_gettime() + if bld.CONFIG_SET('HAVE_LIBRT'): extra_libs += ' rt' + bld.SAMBA_LIBRARY('cmocka', source='cmocka.c', - deps='rt', + deps=extra_libs, allow_warnings=True, private_library=True) -- 2.17.1 From 48cd645d1d81fae6f528e3cc7e83b3d9ad1caefd Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 23 Sep 2019 17:39:29 +0200 Subject: [PATCH 233/376] third_party: Link nss_wrapper against pthread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nss_wrapper uses pthread_atfork() which is only provided by libpthread. So we need an explicit dependency. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Pair-Programmed-With: Isaac Boukris Reviewed-by: Matthias Dieter Wallnöfer Reviewed-by: Alexander Bokovoy (cherry picked from commit 68d8a02ef57cce29e4ff3ef1b792adfc10d0b916) --- third_party/nss_wrapper/wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/nss_wrapper/wscript b/third_party/nss_wrapper/wscript index 127b5207c5e..7a2f53ad299 100644 --- a/third_party/nss_wrapper/wscript +++ b/third_party/nss_wrapper/wscript @@ -90,6 +90,6 @@ def build(bld): # breaks preloading! bld.SAMBA_LIBRARY('nss_wrapper', source='nss_wrapper.c', - deps='dl', + deps='dl pthread', install=False, realname='libnss-wrapper.so') -- 2.17.1 From b5dfe882ecbe5317c12971d83140b59a0d24da6b Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 23 Sep 2019 17:40:13 +0200 Subject: [PATCH 234/376] third_party: Link uid_wrapper against pthread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uid_wrapper uses pthread_atfork() which is only provided by libpthread. │···················· So we need an explicit dependency. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Pair-Programmed-With: Isaac Boukris Reviewed-by: Matthias Dieter Wallnöfer Reviewed-by: Alexander Bokovoy (cherry picked from commit bd0cd8e13234d684da77a65f6fdaea2572625369) --- third_party/uid_wrapper/wscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/uid_wrapper/wscript b/third_party/uid_wrapper/wscript index 61d8a189625..738343f49e4 100644 --- a/third_party/uid_wrapper/wscript +++ b/third_party/uid_wrapper/wscript @@ -119,6 +119,6 @@ def build(bld): # breaks preloading! bld.SAMBA_LIBRARY('uid_wrapper', source='uid_wrapper.c', - deps='dl', + deps='dl pthread', install=False, realname='libuid-wrapper.so') -- 2.17.1 From 0182ccfd22bfd002d9c1d1f04372fccd642cfc0e Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 23 Sep 2019 16:53:12 +0200 Subject: [PATCH 235/376] waf:replace: Do not link against libpthread if not necessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Linux we should avoid linking everything against libpthread. Symbols used my most application are provided by glibc and code which deals with threads has to explicitly link against libpthread. This avoids setting LDFLAGS=-pthread globally. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Pair-Programmed-With: Isaac Boukris Reviewed-by: Matthias Dieter Wallnöfer Reviewed-by: Alexander Bokovoy (cherry picked from commit 9499db075b72b147e2ff9bb78e9d5edbaac14e69) --- lib/replace/wscript | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/replace/wscript b/lib/replace/wscript index ec5e085a350..240d730cbee 100644 --- a/lib/replace/wscript +++ b/lib/replace/wscript @@ -552,6 +552,11 @@ def configure(conf): PTHREAD_CFLAGS='error' PTHREAD_LDFLAGS='error' + if PTHREAD_LDFLAGS == 'error': + # Check if pthread_attr_init() is provided by libc first! + if conf.CHECK_FUNCS('pthread_attr_init'): + PTHREAD_CFLAGS='-D_REENTRANT' + PTHREAD_LDFLAGS='' if PTHREAD_LDFLAGS == 'error': if conf.CHECK_FUNCS_IN('pthread_attr_init', 'pthread'): PTHREAD_CFLAGS='-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS' @@ -564,10 +569,7 @@ def configure(conf): if conf.CHECK_FUNCS_IN('pthread_attr_init', 'c_r'): PTHREAD_CFLAGS='-D_THREAD_SAFE -pthread' PTHREAD_LDFLAGS='-pthread' - if PTHREAD_LDFLAGS == 'error': - if conf.CHECK_FUNCS('pthread_attr_init'): - PTHREAD_CFLAGS='-D_REENTRANT' - PTHREAD_LDFLAGS='-lpthread' + # especially for HP-UX, where the CHECK_FUNC macro fails to test for # pthread_attr_init. On pthread_mutex_lock it works there... if PTHREAD_LDFLAGS == 'error': -- 2.17.1 From 4a43d8b996b1ce444596ed41a686be5ae526113d Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 25 Sep 2019 17:19:27 -0700 Subject: [PATCH 236/376] selftest: Test ID_TYPE_BOTH with idmap_rid module ID_TYPE_BOTH means that each user and group has two mappings, a uid and gid. In addition the calls to getpwent, getpwuid, getgrent and getgrgid always return some information, so that uid and gid can be mapped to a name. Establish a test to verify that the expected information is returned. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14141 Signed-off-by: Christof Schmitt Reviewed-by: Stefan Metzmacher (cherry picked from commit 485874d6bb328c50c9a98785e85270f28ade7497) --- nsswitch/tests/test_idmap_rid.sh | 132 +++++++++++++++++++++++ selftest/knownfail.d/passwd-id-type-both | 4 + 2 files changed, 136 insertions(+) create mode 100644 selftest/knownfail.d/passwd-id-type-both diff --git a/nsswitch/tests/test_idmap_rid.sh b/nsswitch/tests/test_idmap_rid.sh index 8209a50a4fc..4e6477f666e 100755 --- a/nsswitch/tests/test_idmap_rid.sh +++ b/nsswitch/tests/test_idmap_rid.sh @@ -63,4 +63,136 @@ test "$out" = "$SID -> unmapped" ret=$? testit "Bogus SID returns unmapped" test $ret -eq 0 || failed=$(expr $failed + 1) +# +# Test 3: ID_TYPE_BOTH mappings for group +# + +GROUP="$DOMAIN/Domain Users" +GROUP_SID=$($wbinfo --name-to-sid="$GROUP" | sed -e 's/ .*//') + +uid=$($wbinfo --sid-to-uid=$GROUP_SID) +ret=$? +testit "ID_TYPE_BOTH group map to uid succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +testit "ID_TYPE_BOTH group map to uid has result" test -n $uid ||\ + failed=$(expr $failed + 1) + +gid=$($wbinfo --sid-to-gid=$GROUP_SID) +ret=$? +testit "ID_TYPE_BOTH group map to gid succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +testit "ID_TYPE_BOTH group map to gid has result" test -n $gid ||\ + failed=$(expr $failed + 1) + +testit "ID_TYPE_BOTH group uid equals gid" test $uid -eq $gid ||\ + failed=$(expr $failed + 1) + +group_pw="$DOMAIN/domain users:*:$uid:$gid::/home/$DOMAIN/domain users:/bin/false" + +out=$(getent passwd "$GROUP") +ret=$? +testit "getpwnam for ID_TYPE_BOTH group succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +test "$out" = "$group_pw" +ret=$? +testit "getpwnam for ID_TYPE_BOTH group output" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +out=$(getent passwd $uid) +ret=$? +testit "getpwuid for ID_TYPE_BOTH group succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +test "$out" = "$group_pw" +ret=$? +testit "getpwuid for ID_TYPE_BOTH group output" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +group_gr="$DOMAIN/domain users:x:$gid:" + +out=$(getent group "$GROUP") +ret=$? +testit "getgrnam for ID_TYPE_BOTH group succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +test "$out" = "$group_gr" +ret=$? +testit "getgrnam for ID_TYPE_BOTH group output" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +out=$(getent group "$gid") +ret=$? +testit "getgrgid for ID_TYPE_BOTH group succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +test "$out" = "$group_gr" +ret=$? +testit "getgrgid for ID_TYPE_BOTH group output" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +# +# Test 4: ID_TYPE_BOTH mappings for user +# + +dom_users_gid=$gid + +USER="$DOMAIN/Administrator" +USER_SID=$($wbinfo --name-to-sid="$USER" | sed -e 's/ .*//') + +uid=$($wbinfo --sid-to-uid=$USER_SID) +ret=$? +testit "ID_TYPE_BOTH user map to uid succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +testit "ID_TYPE_BOTH user map to uid has result" test -n $uid ||\ + failed=$(expr $failed + 1) + +gid=$($wbinfo --sid-to-gid=$USER_SID) +ret=$? +testit "ID_TYPE_BOTH user map to gid succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +testit "ID_TYPE_BOTH user map to gid has result" test -n $gid ||\ + failed=$(expr $failed + 1) + +testit "ID_TYPE_BOTH user uid equals gid" test $uid -eq $gid ||\ + failed=$(expr $failed + 1) + +user_pw="$DOMAIN/administrator:*:$uid:$dom_users_gid::/home/$DOMAIN/administrator:/bin/false" + +out=$(getent passwd "$USER") +ret=$? +testit "getpwnam for ID_TYPE_BOTH user succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +test "$out" = "$user_pw" +ret=$? +testit "getpwnam for ID_TYPE_BOTH user output" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +out=$(getent passwd $uid) +ret=$? +testit "getpwuid for ID_TYPE_BOTH user succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +test "$out" = "$user_pw" +ret=$? +testit "getpwuid for ID_TYPE_BOTH user output" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +user_gr="$DOMAIN/administrator:x:$gid:$DOMAIN/administrator" + +out=$(getent group "$USER") +ret=$? +testit "getgrnam for ID_TYPE_BOTH user succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +test "$out" = "$user_gr" +ret=$? +testit "getgrnam for ID_TYPE_BOTH user output" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + +out=$(getent group "$gid") +ret=$? +testit "getgrgid for ID_TYPE_BOTH user succeeds" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) +test "$out" = "$user_gr" +ret=$? +testit "getgrgid for ID_TYPE_BOTH user output" test $ret -eq 0 ||\ + failed=$(expr $failed + 1) + exit $failed diff --git a/selftest/knownfail.d/passwd-id-type-both b/selftest/knownfail.d/passwd-id-type-both new file mode 100644 index 00000000000..e969ef8d165 --- /dev/null +++ b/selftest/knownfail.d/passwd-id-type-both @@ -0,0 +1,4 @@ +idmap\.rid.getpwnam for ID_TYPE_BOTH group succeeds\(ad_member_idmap_rid\) +idmap\.rid.getpwnam for ID_TYPE_BOTH group output\(ad_member_idmap_rid\) +idmap\.rid.getpwuid for ID_TYPE_BOTH group succeeds\(ad_member_idmap_rid\) +idmap\.rid.getpwuid for ID_TYPE_BOTH group output\(ad_member_idmap_rid\) -- 2.17.1 From 42d530b0dbc1b1389b393c648357de31e4c11e9f Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Fri, 11 Jan 2019 10:44:30 +0100 Subject: [PATCH 237/376] winbind: provide passwd struct for group sid with ID_TYPE_BOTH mapping (again) https://git.samba.org/?p=samba.git;a=commitdiff;h=394622ef8c916cf361f8596dba4664dc8d6bfc9e originally introduced the above feature. This functionality was undone as part of "winbind: Restructure get_pwsid" https://git.samba.org/?p=samba.git;a=commitdiff;h=bce19a6efe11980933531f0349c8f5212419366a I think that this semantic change was accidential. This patch undoes the semantic change and re-establishes the functionality. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14141 Signed-off-by: Michael Adam Reviewed-by: Christof Schmitt Reviewed-by: Stefan Metzmacher Autobuild-User(master): Christof Schmitt Autobuild-Date(master): Fri Sep 27 17:25:29 UTC 2019 on sn-devel-184 (cherry picked from commit 63c9147f8631d73b52bdd36ff407e0361dcf5178) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Wed Oct 2 11:06:20 UTC 2019 on sn-devel-184 --- selftest/knownfail.d/passwd-id-type-both | 4 ---- source3/winbindd/wb_queryuser.c | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) delete mode 100644 selftest/knownfail.d/passwd-id-type-both diff --git a/selftest/knownfail.d/passwd-id-type-both b/selftest/knownfail.d/passwd-id-type-both deleted file mode 100644 index e969ef8d165..00000000000 --- a/selftest/knownfail.d/passwd-id-type-both +++ /dev/null @@ -1,4 +0,0 @@ -idmap\.rid.getpwnam for ID_TYPE_BOTH group succeeds\(ad_member_idmap_rid\) -idmap\.rid.getpwnam for ID_TYPE_BOTH group output\(ad_member_idmap_rid\) -idmap\.rid.getpwuid for ID_TYPE_BOTH group succeeds\(ad_member_idmap_rid\) -idmap\.rid.getpwuid for ID_TYPE_BOTH group output\(ad_member_idmap_rid\) diff --git a/source3/winbindd/wb_queryuser.c b/source3/winbindd/wb_queryuser.c index 17170c3352a..2eb61406fc5 100644 --- a/source3/winbindd/wb_queryuser.c +++ b/source3/winbindd/wb_queryuser.c @@ -166,8 +166,22 @@ static void wb_queryuser_got_domain(struct tevent_req *subreq) return; } - if (type != SID_NAME_USER) { - /* allow SID_NAME_COMPUTER? */ + switch (type) { + case SID_NAME_USER: + case SID_NAME_COMPUTER: + /* + * user case: we only need the account name from lookup_sids + */ + break; + case SID_NAME_DOM_GRP: + case SID_NAME_ALIAS: + case SID_NAME_WKN_GRP: + /* + * also treat group-type SIDs (they might map to ID_TYPE_BOTH) + */ + sid_copy(&info->group_sid, &info->user_sid); + break; + default: tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER); return; } -- 2.17.1 From e8cba5a8a88b47274305b56132a399117d074476 Mon Sep 17 00:00:00 2001 From: Amitay Isaacs Date: Mon, 30 Sep 2019 16:34:35 +1000 Subject: [PATCH 238/376] ctdb-vacuum: Process all records not deleted on a remote node This currently skips the last record. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14147 RN: Avoid potential data loss during recovery after vacuuming error Signed-off-by: Amitay Isaacs Reviewed-by: Martin Schwenke (cherry picked from commit 33f1c9d9654fbdcb99c23f9d23c4bbe2cc596b98) --- ctdb/server/ctdb_vacuum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_vacuum.c b/ctdb/server/ctdb_vacuum.c index 0c3770267bc..4fd11e3738c 100644 --- a/ctdb/server/ctdb_vacuum.c +++ b/ctdb/server/ctdb_vacuum.c @@ -814,7 +814,7 @@ static void ctdb_process_delete_list(struct ctdb_db_context *ctdb_db, */ records = (struct ctdb_marshall_buffer *)outdata.dptr; rec = (struct ctdb_rec_data_old *)&records->data[0]; - while (records->count-- > 1) { + while (records->count-- > 0) { TDB_DATA reckey, recdata; struct ctdb_ltdb_header *rechdr; struct delete_record_data *dd; -- 2.17.1 From 2ce14ef46a5d5d9ab6b9c30f1fb00debc1be71a4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 3 Oct 2019 14:02:13 -0700 Subject: [PATCH 239/376] s3: smbclient: Stop an SMB2-connection from blundering into SMB1-specific calls. Fix in the same way this was done in SMBC_opendir_ctx() for libsmbclient. This fix means the admin no longer has to remember to set 'min client protocol =' when connecting to an SMB2-only server (MacOSX for example) and trying to list shares. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14152 Signed-off-by: Jeremy Allison Reviewed-by: Andreas Schneider (cherry picked from commit ea82bca8cef0d736305a7a40b3198fc55ea66af8) --- source3/client/client.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/client/client.c b/source3/client/client.c index 7a7ecd92eb6..e1de711c8e4 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -4918,6 +4918,10 @@ static bool browse_host(bool sort) return false; } + if (smbXcli_conn_protocol(cli->conn) > PROTOCOL_NT1) { + return false; + } + ret = cli_RNetShareEnum(cli, browse_fn, NULL); if (ret == -1) { NTSTATUS status = cli_nt_error(cli); -- 2.17.1 From adfcddc681564ff278cbbf243f1a245ec62f0dbe Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 8 Aug 2019 14:35:38 +0200 Subject: [PATCH 240/376] testprogs: Fix failure count in test_net_ads.sh There are missing ` at the end of the line. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13884 Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 320b5be4dce95d8dac4b3c0847faf5b730754a37) --- testprogs/blackbox/test_net_ads.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh index d3c4de5b741..512aa9d2952 100755 --- a/testprogs/blackbox/test_net_ads.sh +++ b/testprogs/blackbox/test_net_ads.sh @@ -141,10 +141,10 @@ testit "test spn service doensn't exist in AD but is present in keytab file afte # SPN parser is very basic but does detect some illegal combination windows_spn="$spn_service/$spn_host:" -testit_expect_failure "test (dedicated keytab) fail to parse windows spn with missing port" $VALGRIND $net_tool ads keytab add $windows_spn -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1 +testit_expect_failure "test (dedicated keytab) fail to parse windows spn with missing port" $VALGRIND $net_tool ads keytab add $windows_spn -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` windows_spn="$spn_service/$spn_host/" -testit_expect_failure "test (dedicated keytab) fail to parse windows spn with missing servicename" $VALGRIND $net_tool ads keytab add $windows_spn -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1 +testit_expect_failure "test (dedicated keytab) fail to parse windows spn with missing servicename" $VALGRIND $net_tool ads keytab add $windows_spn -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` testit "changetrustpw (dedicated keytab)" $VALGRIND $net_tool ads changetrustpw || failed=`expr $failed + 1` -- 2.17.1 From 90566a8ef442fefbd9b8b10789eaebd6349ef266 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 13 Aug 2019 17:06:58 +0200 Subject: [PATCH 241/376] s3:libads: Use ldap_add_ext_s() in ads_gen_add() ldap_add_s() is marked as deprecated. Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 456322a61319a10aaedda5244488ea4e5aa5cb64) --- source3/libads/ldap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 2110390b65f..66aea348e23 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -1596,7 +1596,7 @@ ADS_STATUS ads_gen_add(ADS_STRUCT *ads, const char *new_dn, ADS_MODLIST mods) /* make sure the end of the list is NULL */ mods[i] = NULL; - ret = ldap_add_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods); + ret = ldap_add_ext_s(ads->ldap.ld, utf8_dn, (LDAPMod**)mods, NULL, NULL); ads_print_error(ret, ads->ldap.ld); TALLOC_FREE(utf8_dn); return ADS_ERROR(ret); -- 2.17.1 From 2fa6dc27f37652a4ccc9cd0e5e159e69364b7064 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 13 Aug 2019 17:41:40 +0200 Subject: [PATCH 242/376] s3:libnet: Require sealed LDAP SASL connections for joining Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit b84abb3a46211dc84e52ef95750627e4dd081f2f) --- libgpo/pygpo.c | 2 +- source3/lib/netapi/joindomain.c | 5 ++++- source3/libads/ads_proto.h | 9 ++++++++- source3/libads/ads_struct.c | 14 +++++++++++++- source3/libads/ldap.c | 4 ++-- source3/libnet/libnet_join.c | 3 ++- source3/libsmb/namequery_dc.c | 2 +- source3/printing/nt_printing_ads.c | 6 +++--- source3/utils/net_ads.c | 13 +++++++++---- source3/winbindd/winbindd_ads.c | 5 ++++- source3/winbindd/winbindd_cm.c | 5 ++++- 11 files changed, 51 insertions(+), 17 deletions(-) diff --git a/libgpo/pygpo.c b/libgpo/pygpo.c index b1f788d3a00..581d20e0649 100644 --- a/libgpo/pygpo.c +++ b/libgpo/pygpo.c @@ -210,7 +210,7 @@ static int py_ads_init(ADS *self, PyObject *args, PyObject *kwds) self->ads_ptr = NULL; } /* always succeeds or crashes */ - self->ads_ptr = ads_init(realm, workgroup, ldap_server); + self->ads_ptr = ads_init(realm, workgroup, ldap_server, ADS_SASL_PLAIN); return 0; } diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c index ff2154ba803..8d0752f4531 100644 --- a/source3/lib/netapi/joindomain.c +++ b/source3/lib/netapi/joindomain.c @@ -411,7 +411,10 @@ WERROR NetGetJoinableOUs_l(struct libnetapi_ctx *ctx, dc = strip_hostname(info->dc_unc); - ads = ads_init(info->domain_name, info->domain_name, dc); + ads = ads_init(info->domain_name, + info->domain_name, + dc, + ADS_SASL_PLAIN); if (!ads) { return WERR_GEN_FAILURE; } diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h index 154bf67f964..92bb3a22cdb 100644 --- a/source3/libads/ads_proto.h +++ b/source3/libads/ads_proto.h @@ -32,6 +32,12 @@ #ifndef _LIBADS_ADS_PROTO_H_ #define _LIBADS_ADS_PROTO_H_ +enum ads_sasl_state_e { + ADS_SASL_PLAIN = 0, + ADS_SASL_SIGN, + ADS_SASL_SEAL, +}; + /* The following definitions come from libads/ads_struct.c */ char *ads_build_path(const char *realm, const char *sep, const char *field, int reverse); @@ -39,7 +45,8 @@ char *ads_build_dn(const char *realm); char *ads_build_domain(const char *dn); ADS_STRUCT *ads_init(const char *realm, const char *workgroup, - const char *ldap_server); + const char *ldap_server, + enum ads_sasl_state_e sasl_state); bool ads_set_sasl_wrap_flags(ADS_STRUCT *ads, int flags); void ads_destroy(ADS_STRUCT **ads); diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c index 3ab682c0e38..043a1b21247 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -132,7 +132,8 @@ char *ads_build_domain(const char *dn) */ ADS_STRUCT *ads_init(const char *realm, const char *workgroup, - const char *ldap_server) + const char *ldap_server, + enum ads_sasl_state_e sasl_state) { ADS_STRUCT *ads; int wrap_flags; @@ -152,6 +153,17 @@ ADS_STRUCT *ads_init(const char *realm, wrap_flags = 0; } + switch (sasl_state) { + case ADS_SASL_PLAIN: + break; + case ADS_SASL_SIGN: + wrap_flags |= ADS_AUTH_SASL_SIGN; + break; + case ADS_SASL_SEAL: + wrap_flags |= ADS_AUTH_SASL_SEAL; + break; + } + ads->auth.flags = wrap_flags; /* Start with the configured page size when the connection is new, diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 66aea348e23..2dc204f1ae8 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -2966,7 +2966,7 @@ ADS_STATUS ads_current_time(ADS_STRUCT *ads) if ( !ads->ldap.ld ) { if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup, - ads->server.ldap_server )) == NULL ) + ads->server.ldap_server, ADS_SASL_PLAIN )) == NULL ) { status = ADS_ERROR(LDAP_NO_MEMORY); goto done; @@ -3028,7 +3028,7 @@ ADS_STATUS ads_domain_func_level(ADS_STRUCT *ads, uint32_t *val) if ( !ads->ldap.ld ) { if ( (ads_s = ads_init( ads->server.realm, ads->server.workgroup, - ads->server.ldap_server )) == NULL ) + ads->server.ldap_server, ADS_SASL_PLAIN )) == NULL ) { status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); goto done; diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index b876d7ea89f..a512afc238a 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -140,7 +140,8 @@ static ADS_STATUS libnet_connect_ads(const char *dns_domain_name, my_ads = ads_init(dns_domain_name, netbios_domain_name, - dc_name); + dc_name, + ADS_SASL_SEAL); if (!my_ads) { return ADS_ERROR_LDAP(LDAP_NO_MEMORY); } diff --git a/source3/libsmb/namequery_dc.c b/source3/libsmb/namequery_dc.c index 4ee5b5278e4..f63dde61603 100644 --- a/source3/libsmb/namequery_dc.c +++ b/source3/libsmb/namequery_dc.c @@ -69,7 +69,7 @@ static bool ads_dc_name(const char *domain, /* Try this 3 times then give up. */ for( i =0 ; i < 3; i++) { - ads = ads_init(realm, domain, NULL); + ads = ads_init(realm, domain, NULL, ADS_SASL_PLAIN); if (!ads) { TALLOC_FREE(sitename); return False; diff --git a/source3/printing/nt_printing_ads.c b/source3/printing/nt_printing_ads.c index 2588e1de7e7..a82f1361fc8 100644 --- a/source3/printing/nt_printing_ads.c +++ b/source3/printing/nt_printing_ads.c @@ -227,7 +227,7 @@ WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer, return WERR_NOT_ENOUGH_MEMORY; } - ads = ads_init(lp_realm(), lp_workgroup(), NULL); + ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN); if (ads == NULL) { result = WERR_RPC_S_SERVER_UNAVAILABLE; goto out; @@ -577,7 +577,7 @@ WERROR nt_printer_publish(TALLOC_CTX *mem_ctx, TALLOC_FREE(sinfo2); - ads = ads_init(lp_realm(), lp_workgroup(), NULL); + ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN); if (!ads) { DEBUG(3, ("ads_init() failed\n")); win_rc = WERR_RPC_S_SERVER_UNAVAILABLE; @@ -633,7 +633,7 @@ WERROR check_published_printers(struct messaging_context *msg_ctx) tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return WERR_NOT_ENOUGH_MEMORY; - ads = ads_init(lp_realm(), lp_workgroup(), NULL); + ads = ads_init(lp_realm(), lp_workgroup(), NULL, ADS_SASL_PLAIN); if (!ads) { DEBUG(3, ("ads_init() failed\n")); return WERR_RPC_S_SERVER_UNAVAILABLE; diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 4a0f59a1e80..19ac9e4533f 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -620,7 +620,10 @@ retry_connect: realm = assume_own_realm(c); } - ads = ads_init(realm, c->opt_target_workgroup, c->opt_host); + ads = ads_init(realm, + c->opt_target_workgroup, + c->opt_host, + ADS_SASL_PLAIN); if (!c->opt_user_name) { c->opt_user_name = "administrator"; @@ -729,7 +732,8 @@ static int net_ads_check_int(const char *realm, const char *workgroup, const cha ADS_STRUCT *ads; ADS_STATUS status; - if ( (ads = ads_init( realm, workgroup, host )) == NULL ) { + ads = ads_init(realm, workgroup, host, ADS_SASL_PLAIN); + if (ads == NULL ) { return -1; } @@ -1764,7 +1768,7 @@ static void _net_ads_join_dns_updates(struct net_context *c, TALLOC_CTX *ctx, st * kinit with the machine password to do dns update. */ - ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name); + ads_dns = ads_init(lp_realm(), NULL, r->in.dc_name, ADS_SASL_PLAIN); if (ads_dns == NULL) { d_fprintf(stderr, _("DNS update failed: out of memory!\n")); @@ -2655,7 +2659,8 @@ static int net_ads_password(struct net_context *c, int argc, const char **argv) /* use the realm so we can eventually change passwords for users in realms other than default */ - if (!(ads = ads_init(realm, c->opt_workgroup, c->opt_host))) { + ads = ads_init(realm, c->opt_workgroup, c->opt_host, ADS_SASL_PLAIN); + if (ads == NULL) { return -1; } diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index 485ca831be9..20f47eb5954 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -110,7 +110,10 @@ static ADS_STATUS ads_cached_connection_connect(ADS_STRUCT **adsp, /* we don't want this to affect the users ccache */ setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); - ads = ads_init(target_realm, target_dom_name, ldap_server); + ads = ads_init(target_realm, + target_dom_name, + ldap_server, + ADS_SASL_SEAL); if (!ads) { DEBUG(1,("ads_init for domain %s failed\n", target_dom_name)); return ADS_ERROR(LDAP_NO_MEMORY); diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index b9a1c1eda7b..0e671ca22be 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -1414,7 +1414,10 @@ static bool dcip_check_name(TALLOC_CTX *mem_ctx, print_sockaddr(addr, sizeof(addr), pss); - ads = ads_init(domain->alt_name, domain->name, addr); + ads = ads_init(domain->alt_name, + domain->name, + addr, + ADS_SASL_PLAIN); ads->auth.flags |= ADS_AUTH_NO_BIND; ads->config.flags |= request_flags; ads->server.no_fallback = true; -- 2.17.1 From 96ee2408f5ca85d84e341d642848a2532661a1f5 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 13 Aug 2019 16:30:07 +0200 Subject: [PATCH 243/376] s3:libads: Cleanup error code paths in ads_create_machine_acct() Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 8ed993789f93624b7b60dd5314fe5472e69e903a) --- source3/libads/ldap.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 2dc204f1ae8..a0bc5fe6741 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -2092,11 +2092,12 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, uint32_t etype_list) { ADS_STATUS ret; - char *samAccountName, *controlstr; - TALLOC_CTX *ctx; + char *samAccountName = NULL; + char *controlstr = NULL; + TALLOC_CTX *ctx = NULL; ADS_MODLIST mods; char *machine_escaped = NULL; - char *new_dn; + char *new_dn = NULL; const char *objectClass[] = {"top", "person", "organizationalPerson", "user", "computer", NULL}; LDAPMessage *res = NULL; @@ -2110,13 +2111,14 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, return ret; } - if (!(ctx = talloc_init("ads_add_machine_acct"))) + ctx = talloc_init("ads_add_machine_acct"); + if (ctx == NULL) { return ADS_ERROR(LDAP_NO_MEMORY); - - ret = ADS_ERROR(LDAP_NO_MEMORY); + } machine_escaped = escape_rdn_val_string_alloc(machine_name); - if (!machine_escaped) { + if (machine_escaped == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); goto done; } @@ -2131,17 +2133,26 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, ads_msgfree(ads, res); new_dn = talloc_asprintf(ctx, "cn=%s,%s", machine_escaped, org_unit); - samAccountName = talloc_asprintf(ctx, "%s$", machine_name); + if (new_dn == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } - if ( !new_dn || !samAccountName ) { + samAccountName = talloc_asprintf(ctx, "%s$", machine_name); + if (samAccountName == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); goto done; } - if (!(controlstr = talloc_asprintf(ctx, "%u", acct_control))) { + controlstr = talloc_asprintf(ctx, "%u", acct_control); + if (controlstr == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); goto done; } - if (!(mods = ads_init_mods(ctx))) { + mods = ads_init_mods(ctx); + if (mods == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); goto done; } @@ -2155,6 +2166,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, etype_list_str = talloc_asprintf(ctx, "%d", (int)etype_list); if (etype_list_str == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); goto done; } ads_mod_str(ctx, &mods, "msDS-SupportedEncryptionTypes", -- 2.17.1 From 023a59d4262c1de4b0d62de0c75a905c0ea658e8 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 21 Aug 2019 12:22:32 +0200 Subject: [PATCH 244/376] s3:libads: Use a talloc_asprintf in ads_find_machine_acct() Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 35f3e4aed1f1c2ba1c8dc50921f238937f343357) --- source3/libads/ldap.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index a0bc5fe6741..f799c8f45d8 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -1367,18 +1367,22 @@ char *ads_parent_dn(const char *dn) ADS_STATUS status; char *expr; const char *attrs[] = {"*", "msDS-SupportedEncryptionTypes", "nTSecurityDescriptor", NULL}; + TALLOC_CTX *frame = talloc_stackframe(); *res = NULL; /* the easiest way to find a machine account anywhere in the tree is to look for hostname$ */ - if (asprintf(&expr, "(samAccountName=%s$)", machine) == -1) { - DEBUG(1, ("asprintf failed!\n")); - return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + expr = talloc_asprintf(frame, "(samAccountName=%s$)", machine); + if (expr == NULL) { + status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); + goto done; } status = ads_search(ads, res, expr, attrs); - SAFE_FREE(expr); + +done: + TALLOC_FREE(frame); return status; } -- 2.17.1 From 8cc6e035b6e68267d608e1d727d6e66b92823655 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 14 Aug 2019 13:01:19 +0200 Subject: [PATCH 245/376] s3:libads: Fix detection if acount already exists in ads_find_machine_count() Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 4f389c1f78cdc2424795e3b2a1ce43818c400c2d) --- source3/libads/ldap.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index f799c8f45d8..ea0d79a3600 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -1366,7 +1366,21 @@ char *ads_parent_dn(const char *dn) { ADS_STATUS status; char *expr; - const char *attrs[] = {"*", "msDS-SupportedEncryptionTypes", "nTSecurityDescriptor", NULL}; + const char *attrs[] = { + /* This is how Windows checks for machine accounts */ + "objectClass", + "SamAccountName", + "userAccountControl", + "DnsHostName", + "ServicePrincipalName", + "unicodePwd", + + /* Additional attributes Samba checks */ + "msDS-SupportedEncryptionTypes", + "nTSecurityDescriptor", + + NULL + }; TALLOC_CTX *frame = talloc_stackframe(); *res = NULL; @@ -1380,6 +1394,11 @@ char *ads_parent_dn(const char *dn) } status = ads_search(ads, res, expr, attrs); + if (ADS_ERR_OK(status)) { + if (ads_count_replies(ads, *res) != 1) { + status = ADS_ERROR_LDAP(LDAP_NO_SUCH_OBJECT); + } + } done: TALLOC_FREE(frame); @@ -1867,11 +1886,11 @@ ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machin char *dn_string = NULL; ret = ads_find_machine_acct(ads, &res, machine_name); - if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) { + if (!ADS_ERR_OK(ret)) { DEBUG(5,("ads_clear_service_principal_names: WARNING: Host Account for %s not found... skipping operation.\n", machine_name)); DEBUG(5,("ads_clear_service_principal_names: WARNING: Service Principals for %s have NOT been cleared.\n", machine_name)); ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + return ret; } DEBUG(5,("ads_clear_service_principal_names: Host account for %s found\n", machine_name)); @@ -2027,12 +2046,12 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads, const char **servicePrincipalName = spns; ret = ads_find_machine_acct(ads, &res, machine_name); - if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) { + if (!ADS_ERR_OK(ret)) { DEBUG(1,("ads_add_service_principal_name: WARNING: Host Account for %s not found... skipping operation.\n", machine_name)); DEBUG(1,("ads_add_service_principal_name: WARNING: Service Principals have NOT been added.\n")); ads_msgfree(ads, res); - return ADS_ERROR(LDAP_NO_SUCH_OBJECT); + return ret; } DEBUG(1,("ads_add_service_principal_name: Host account for %s found\n", machine_name)); @@ -2127,7 +2146,7 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, } ret = ads_find_machine_acct(ads, &res, machine_escaped); - if (ADS_ERR_OK(ret) && ads_count_replies(ads, res) == 1) { + if (ADS_ERR_OK(ret)) { DBG_DEBUG("Host account for %s already exists.\n", machine_escaped); ret = ADS_ERROR_LDAP(LDAP_ALREADY_EXISTS); @@ -3688,14 +3707,15 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) TALLOC_FREE(hostnameDN); status = ads_find_machine_acct(ads, &res, host); - if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) { + if ((status.error_type == ENUM_ADS_ERROR_LDAP) && + (status.err.rc != LDAP_NO_SUCH_OBJECT)) { DEBUG(3, ("Failed to remove host account.\n")); SAFE_FREE(host); return status; } SAFE_FREE(host); - return status; + return ADS_SUCCESS; } /** -- 2.17.1 From e0be43a863bba4be3df81b8a7b7a95f99bfb4783 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 14 Aug 2019 12:17:20 +0200 Subject: [PATCH 246/376] s3:libads: Don't set supported encryption types during account creation This is already handled by libnet_join_post_processing_ads_modify() which calls libnet_join_set_etypes() if encrytion types should be set. Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit b755a6438022579dab1a403c81d60b1ed7efca38) --- source3/libads/ldap.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index ea0d79a3600..cdefe290c28 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -2127,12 +2127,6 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\ UF_DONT_EXPIRE_PASSWD |\ UF_ACCOUNTDISABLE ); - uint32_t func_level = 0; - - ret = ads_domain_func_level(ads, &func_level); - if (!ADS_ERR_OK(ret)) { - return ret; - } ctx = talloc_init("ads_add_machine_acct"); if (ctx == NULL) { @@ -2184,18 +2178,6 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, ads_mod_strlist(ctx, &mods, "objectClass", objectClass); ads_mod_str(ctx, &mods, "userAccountControl", controlstr); - if (func_level >= DS_DOMAIN_FUNCTION_2008) { - const char *etype_list_str; - - etype_list_str = talloc_asprintf(ctx, "%d", (int)etype_list); - if (etype_list_str == NULL) { - ret = ADS_ERROR(LDAP_NO_MEMORY); - goto done; - } - ads_mod_str(ctx, &mods, "msDS-SupportedEncryptionTypes", - etype_list_str); - } - ret = ads_gen_add(ads, new_dn, mods); done: -- 2.17.1 From 86e86cddcb5b6e0319605e1c46fe1932b3e81bf1 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Tue, 13 Aug 2019 16:34:34 +0200 Subject: [PATCH 247/376] s3:libads: Fix creating machine account using LDAP This implements the same behaviour as Windows. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13884 Pair-Programmed-With: Guenther Deschner Signed-off-by: Guenther Deschner Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit ce7762935051c862ecdd3e82d93096aac61dd292) --- source3/libads/ads_proto.h | 4 +- source3/libads/ldap.c | 118 +++++++++++++++++++++++++++++++---- source3/libnet/libnet_join.c | 23 ++++--- 3 files changed, 124 insertions(+), 21 deletions(-) diff --git a/source3/libads/ads_proto.h b/source3/libads/ads_proto.h index 92bb3a22cdb..495ef5d3325 100644 --- a/source3/libads/ads_proto.h +++ b/source3/libads/ads_proto.h @@ -114,8 +114,10 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads, const char *machine_ const char **spns); ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, + const char *machine_password, const char *org_unit, - uint32_t etype_list); + uint32_t etype_list, + const char *dns_domain_name); ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name, const char *org_unit, bool *moved); int ads_count_replies(ADS_STRUCT *ads, void *res); diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index cdefe290c28..928c0da5af9 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -1516,7 +1516,6 @@ ADS_STATUS ads_mod_strlist(TALLOC_CTX *ctx, ADS_MODLIST *mods, name, (const void **) vals); } -#if 0 /** * Add a single ber-encoded value to a mod list * @param ctx An initialized TALLOC_CTX @@ -1537,7 +1536,6 @@ static ADS_STATUS ads_mod_ber(TALLOC_CTX *ctx, ADS_MODLIST *mods, return ads_modlist_add(ctx, mods, LDAP_MOD_REPLACE|LDAP_MOD_BVALUES, name, (const void **) values); } -#endif static void ads_print_error(int ret, LDAP *ld) { @@ -2111,8 +2109,10 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads, ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, const char *machine_name, + const char *machine_password, const char *org_unit, - uint32_t etype_list) + uint32_t etype_list, + const char *dns_domain_name) { ADS_STATUS ret; char *samAccountName = NULL; @@ -2120,13 +2120,23 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, TALLOC_CTX *ctx = NULL; ADS_MODLIST mods; char *machine_escaped = NULL; + char *dns_hostname = NULL; char *new_dn = NULL; - const char *objectClass[] = {"top", "person", "organizationalPerson", - "user", "computer", NULL}; + char *utf8_pw = NULL; + size_t utf8_pw_len = 0; + char *utf16_pw = NULL; + size_t utf16_pw_len = 0; + struct berval machine_pw_val; + bool ok; + const char **spn_array = NULL; + size_t num_spns = 0; + const char *spn_prefix[] = { + "HOST", + "RestrictedKrbHost", + }; + size_t i; LDAPMessage *res = NULL; - uint32_t acct_control = ( UF_WORKSTATION_TRUST_ACCOUNT |\ - UF_DONT_EXPIRE_PASSWD |\ - UF_ACCOUNTDISABLE ); + uint32_t acct_control = UF_WORKSTATION_TRUST_ACCOUNT; ctx = talloc_init("ads_add_machine_acct"); if (ctx == NULL) { @@ -2139,10 +2149,9 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, goto done; } + /* Check if the machine account already exists. */ ret = ads_find_machine_acct(ads, &res, machine_escaped); if (ADS_ERR_OK(ret)) { - DBG_DEBUG("Host account for %s already exists.\n", - machine_escaped); ret = ADS_ERROR_LDAP(LDAP_ALREADY_EXISTS); ads_msgfree(ads, res); goto done; @@ -2155,28 +2164,111 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, goto done; } + /* Create machine account */ + samAccountName = talloc_asprintf(ctx, "%s$", machine_name); if (samAccountName == NULL) { ret = ADS_ERROR(LDAP_NO_MEMORY); goto done; } + dns_hostname = talloc_asprintf(ctx, + "%s.%s", + machine_name, + dns_domain_name); + if (dns_hostname == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + + /* Add dns_hostname SPNs */ + for (i = 0; i < ARRAY_SIZE(spn_prefix); i++) { + char *spn = talloc_asprintf(ctx, + "%s/%s", + spn_prefix[i], + dns_hostname); + if (spn == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + + ok = add_string_to_array(spn_array, + spn, + &spn_array, + &num_spns); + if (!ok) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + } + + /* Add machine_name SPNs */ + for (i = 0; i < ARRAY_SIZE(spn_prefix); i++) { + char *spn = talloc_asprintf(ctx, + "%s/%s", + spn_prefix[i], + machine_name); + if (spn == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + + ok = add_string_to_array(spn_array, + spn, + &spn_array, + &num_spns); + if (!ok) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + } + + /* Make sure to NULL terminate the array */ + spn_array = talloc_realloc(ctx, spn_array, const char *, num_spns + 1); + if (spn_array == NULL) { + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + } + spn_array[num_spns] = NULL; + controlstr = talloc_asprintf(ctx, "%u", acct_control); if (controlstr == NULL) { ret = ADS_ERROR(LDAP_NO_MEMORY); goto done; } + utf8_pw = talloc_asprintf(ctx, "\"%s\"", machine_password); + if (utf8_pw == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + utf8_pw_len = strlen(utf8_pw); + + ok = convert_string_talloc(ctx, + CH_UTF8, CH_UTF16MUNGED, + utf8_pw, utf8_pw_len, + (void *)&utf16_pw, &utf16_pw_len); + if (!ok) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + + machine_pw_val = (struct berval) { + .bv_val = utf16_pw, + .bv_len = utf16_pw_len, + }; + mods = ads_init_mods(ctx); if (mods == NULL) { ret = ADS_ERROR(LDAP_NO_MEMORY); goto done; } - ads_mod_str(ctx, &mods, "cn", machine_name); - ads_mod_str(ctx, &mods, "sAMAccountName", samAccountName); - ads_mod_strlist(ctx, &mods, "objectClass", objectClass); + ads_mod_str(ctx, &mods, "objectClass", "Computer"); + ads_mod_str(ctx, &mods, "SamAccountName", samAccountName); ads_mod_str(ctx, &mods, "userAccountControl", controlstr); + ads_mod_str(ctx, &mods, "DnsHostName", dns_hostname); + ads_mod_strlist(ctx, &mods, "ServicePrincipalName", spn_array); + ads_mod_ber(ctx, &mods, "unicodePwd", &machine_pw_val); ret = ads_gen_add(ads, new_dn, mods); diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index a512afc238a..d5c8599beee 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -338,10 +338,22 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx, /* Attempt to create the machine account and bail if this fails. Assume that the admin wants exactly what they requested */ + if (r->in.machine_password == NULL) { + r->in.machine_password = + trust_pw_new_value(mem_ctx, + r->in.secure_channel_type, + SEC_ADS); + if (r->in.machine_password == NULL) { + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + } + } + status = ads_create_machine_acct(r->in.ads, r->in.machine_name, + r->in.machine_password, r->in.account_ou, - r->in.desired_encryption_types); + r->in.desired_encryption_types, + r->out.dns_domain_name); if (ADS_ERR_OK(status)) { DEBUG(1,("machine account creation created\n")); @@ -2668,12 +2680,11 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx, if (ADS_ERR_OK(ads_status)) { /* - * LDAP object create succeeded, now go to the rpc - * password set routines + * LDAP object creation succeeded. */ - r->in.join_flags &= ~WKSSVC_JOIN_FLAGS_ACCOUNT_CREATE; - goto rpc_join; + + return WERR_OK; } if (initial_account_ou != NULL) { @@ -2687,8 +2698,6 @@ static WERROR libnet_DomainJoin(TALLOC_CTX *mem_ctx, DBG_INFO("Failed to pre-create account in OU %s: %s\n", r->in.account_ou, ads_errstr(ads_status)); } - rpc_join: - #endif /* HAVE_ADS */ if ((r->in.join_flags & WKSSVC_JOIN_FLAGS_JOIN_UNSECURE) && -- 2.17.1 From 8fa84176dbcc268492f07f92d8baf3156877f78a Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 14 Aug 2019 10:15:19 +0200 Subject: [PATCH 248/376] s3:libnet: Improve debug messages Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 39b8c8b30a5d5bd70f8da3a02cf77f7592788b94) --- source3/libnet/libnet_join.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index d5c8599beee..31d1d221ed3 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -356,7 +356,7 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx, r->out.dns_domain_name); if (ADS_ERR_OK(status)) { - DEBUG(1,("machine account creation created\n")); + DBG_WARNING("Machine account successfully created\n"); return status; } else if ((status.error_type == ENUM_ADS_ERROR_LDAP) && (status.err.rc == LDAP_ALREADY_EXISTS)) { @@ -364,7 +364,7 @@ static ADS_STATUS libnet_join_precreate_machine_acct(TALLOC_CTX *mem_ctx, } if (!ADS_ERR_OK(status)) { - DEBUG(1,("machine account creation failed\n")); + DBG_WARNING("Failed to create machine account\n"); return status; } -- 2.17.1 From 440c8890798d6ac7a75f41f0ea0d1f98d234eb6b Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 8 Aug 2019 14:40:04 +0200 Subject: [PATCH 249/376] s3:libads: Just change the machine password if account already exists BUG: https://bugzilla.samba.org/show_bug.cgi?id=13884 Pair-Programmed-With: Guenther Deschner Signed-off-by: Guenther Deschner Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 14f320fa1e40ecc3a43dabb0cecd57430270a521) --- source3/libads/ldap.c | 167 ++++++++++++++++++++++++++++++----- source3/libnet/libnet_join.c | 1 + 2 files changed, 146 insertions(+), 22 deletions(-) diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index 928c0da5af9..979192eb3ed 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -2098,6 +2098,127 @@ ADS_STATUS ads_add_service_principal_names(ADS_STRUCT *ads, return ret; } +static uint32_t ads_get_acct_ctrl(ADS_STRUCT *ads, + LDAPMessage *msg) +{ + uint32_t acct_ctrl = 0; + bool ok; + + ok = ads_pull_uint32(ads, msg, "userAccountControl", &acct_ctrl); + if (!ok) { + return 0; + } + + return acct_ctrl; +} + +static ADS_STATUS ads_change_machine_acct(ADS_STRUCT *ads, + LDAPMessage *msg, + const struct berval *machine_pw_val) +{ + ADS_MODLIST mods; + ADS_STATUS ret; + TALLOC_CTX *frame = talloc_stackframe(); + uint32_t acct_control; + char *control_str = NULL; + const char *attrs[] = { + "objectSid", + NULL + }; + LDAPMessage *res = NULL; + char *dn = NULL; + + dn = ads_get_dn(ads, frame, msg); + if (dn == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + + acct_control = ads_get_acct_ctrl(ads, msg); + if (acct_control == 0) { + ret = ADS_ERROR(LDAP_NO_RESULTS_RETURNED); + goto done; + } + + /* + * Changing the password, disables the account. So we need to change the + * userAccountControl flags to enable it again. + */ + mods = ads_init_mods(frame); + if (mods == NULL) { + ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; + } + + ads_mod_ber(frame, &mods, "unicodePwd", machine_pw_val); + + ret = ads_gen_mod(ads, dn, mods); + if (!ADS_ERR_OK(ret)) { + goto done; + } + TALLOC_FREE(mods); + + /* + * To activate the account, we need to disable and enable it. + */ + acct_control |= UF_ACCOUNTDISABLE; + + control_str = talloc_asprintf(frame, "%u", acct_control); + if (control_str == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + + mods = ads_init_mods(frame); + if (mods == NULL) { + ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; + } + + ads_mod_str(frame, &mods, "userAccountControl", control_str); + + ret = ads_gen_mod(ads, dn, mods); + if (!ADS_ERR_OK(ret)) { + goto done; + } + TALLOC_FREE(mods); + TALLOC_FREE(control_str); + + /* + * Enable the account again. + */ + acct_control &= ~UF_ACCOUNTDISABLE; + + control_str = talloc_asprintf(frame, "%u", acct_control); + if (control_str == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + + mods = ads_init_mods(frame); + if (mods == NULL) { + ret = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; + } + + ads_mod_str(frame, &mods, "userAccountControl", control_str); + + ret = ads_gen_mod(ads, dn, mods); + if (!ADS_ERR_OK(ret)) { + goto done; + } + TALLOC_FREE(mods); + TALLOC_FREE(control_str); + + ret = ads_search_dn(ads, &res, dn, attrs); + ads_msgfree(ads, res); + +done: + talloc_free(frame); + + return ret; +} + /** * adds a machine account to the ADS server * @param ads An intialized ADS_STRUCT @@ -2149,11 +2270,34 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, goto done; } + utf8_pw = talloc_asprintf(ctx, "\"%s\"", machine_password); + if (utf8_pw == NULL) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + utf8_pw_len = strlen(utf8_pw); + + ok = convert_string_talloc(ctx, + CH_UTF8, CH_UTF16MUNGED, + utf8_pw, utf8_pw_len, + (void *)&utf16_pw, &utf16_pw_len); + if (!ok) { + ret = ADS_ERROR(LDAP_NO_MEMORY); + goto done; + } + + machine_pw_val = (struct berval) { + .bv_val = utf16_pw, + .bv_len = utf16_pw_len, + }; + /* Check if the machine account already exists. */ ret = ads_find_machine_acct(ads, &res, machine_escaped); if (ADS_ERR_OK(ret)) { - ret = ADS_ERROR_LDAP(LDAP_ALREADY_EXISTS); + /* Change the machine account password */ + ret = ads_change_machine_acct(ads, res, &machine_pw_val); ads_msgfree(ads, res); + goto done; } ads_msgfree(ads, res); @@ -2236,27 +2380,6 @@ ADS_STATUS ads_create_machine_acct(ADS_STRUCT *ads, goto done; } - utf8_pw = talloc_asprintf(ctx, "\"%s\"", machine_password); - if (utf8_pw == NULL) { - ret = ADS_ERROR(LDAP_NO_MEMORY); - goto done; - } - utf8_pw_len = strlen(utf8_pw); - - ok = convert_string_talloc(ctx, - CH_UTF8, CH_UTF16MUNGED, - utf8_pw, utf8_pw_len, - (void *)&utf16_pw, &utf16_pw_len); - if (!ok) { - ret = ADS_ERROR(LDAP_NO_MEMORY); - goto done; - } - - machine_pw_val = (struct berval) { - .bv_val = utf16_pw, - .bv_len = utf16_pw_len, - }; - mods = ads_init_mods(ctx); if (mods == NULL) { ret = ADS_ERROR(LDAP_NO_MEMORY); diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index 31d1d221ed3..1052afde641 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -968,6 +968,7 @@ static ADS_STATUS libnet_join_post_processing_ads_modify(TALLOC_CTX *mem_ctx, if (r->in.ads->auth.ccache_name != NULL) { ads_kdestroy(r->in.ads->auth.ccache_name); + r->in.ads->auth.ccache_name = NULL; } ads_destroy(&r->in.ads); -- 2.17.1 From 8d426b146e7f9ba04dc07779d810bd7c8fcd4b10 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 22 Aug 2019 16:31:30 +0200 Subject: [PATCH 250/376] testprogs: Add test for 'net ads join createcomputer=' Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Wed Oct 9 08:26:17 UTC 2019 on sn-devel-184 (cherry picked from commit 459b43e5776180dc1540cd845b72ff78747ecd6f) --- testprogs/blackbox/test_net_ads.sh | 32 ++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh index 512aa9d2952..cc8345c4624 100755 --- a/testprogs/blackbox/test_net_ads.sh +++ b/testprogs/blackbox/test_net_ads.sh @@ -31,6 +31,16 @@ if [ -x "$BINDIR/ldbsearch" ]; then ldbsearch="$BINDIR/ldbsearch" fi +ldbadd="ldbadd" +if [ -x "$BINDIR/ldbadd" ]; then + ldbadd="$BINDIR/ldbadd" +fi + +ldbdel="ldbdel" +if [ -x "$BINDIR/ldbdel" ]; then + ldbdel="$BINDIR/ldbdel" +fi + # Load test functions . `dirname $0`/subunit.sh @@ -188,8 +198,9 @@ testit "testjoin user+password" $VALGRIND $net_tool ads testjoin -U$DC_USERNAME% testit "leave+keep_account" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD --keep-account || failed=`expr $failed + 1` -computers_ldb_ou="CN=Computers,DC=addom,DC=samba,DC=example,DC=com" -testit "ldb check for existence of machine account" $ldbsearch -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "cn=$HOSTNAME,$computers_ldb_ou" || failed=`expr $failed + 1` +base_dn="DC=addom,DC=samba,DC=example,DC=com" +computers_dn="CN=Computers,$base_dn" +testit "ldb check for existence of machine account" $ldbsearch -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "cn=$HOSTNAME,$computers_dn" || failed=`expr $failed + 1` testit "join" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` @@ -198,6 +209,23 @@ testit "testjoin" $VALGRIND $net_tool ads testjoin || failed=`expr $failed + 1` ##Goodbye... testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` +# +# Test createcomputer option of 'net ads join' +# +testit "Create OU=Servers,$base_dn" $VALGRIND $ldbadd -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER < Date: Wed, 25 Sep 2019 23:44:49 +0200 Subject: [PATCH 251/376] libcli/auth: add test for gensec_schannel code Guenther Signed-off-by: Guenther Deschner Pair-Programmed-With: Stefan Metzmacher Reviewed-by: Andreas Schneider (cherry picked from commit 7eae4280d23404be7d27f65a0c817bea2e0084b6) --- libcli/auth/tests/test_schannel.c | 305 ++++++++++++++++++++++++++++++ libcli/auth/wscript_build | 8 + selftest/knownfail | 1 + selftest/tests.py | 2 + 4 files changed, 316 insertions(+) create mode 100644 libcli/auth/tests/test_schannel.c diff --git a/libcli/auth/tests/test_schannel.c b/libcli/auth/tests/test_schannel.c new file mode 100644 index 00000000000..b1c88fdf667 --- /dev/null +++ b/libcli/auth/tests/test_schannel.c @@ -0,0 +1,305 @@ +/* + * Unix SMB/CIFS implementation. + * + * Copyright (C) 2019 Guenther Deschner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#include "includes.h" +#include "auth/gensec/schannel.c" + +static void torture_schannel_seal_flags(void **state, uint32_t flags, + const DATA_BLOB session_key, + const DATA_BLOB seq_num_initial, + const DATA_BLOB confounder_initial, + const DATA_BLOB confounder_expected, + const DATA_BLOB clear_initial, + const DATA_BLOB crypt_expected) +{ + NTSTATUS status; + struct schannel_state *schannel_state; + struct netlogon_creds_CredentialState *creds; + uint8_t confounder[8]; + DATA_BLOB io; + + assert_int_equal(session_key.length, 16); + assert_int_equal(seq_num_initial.length, 8); + assert_int_equal(confounder_initial.length, 8); + assert_int_equal(confounder_expected.length, 8); + assert_int_equal(clear_initial.length, crypt_expected.length); + + DEBUG(0,("checking buffer size: %d\n", (int)clear_initial.length)); + + schannel_state = talloc_zero(NULL, struct schannel_state); + assert_non_null(schannel_state); + creds = talloc_zero(schannel_state, + struct netlogon_creds_CredentialState); + assert_non_null(creds); + schannel_state->creds = creds; + + io = data_blob_dup_talloc(schannel_state, clear_initial); + assert_non_null(io.data); + assert_int_equal(io.length, clear_initial.length); + + schannel_state->creds->negotiate_flags = flags; + memcpy(schannel_state->creds->session_key, session_key.data, 16); + + memcpy(confounder, confounder_initial.data, 8); + + DEBUG(0,("confounder before crypt:\n")); + dump_data(0, confounder, 8); + dump_data(0, seq_num_initial.data, 8); + dump_data(0, io.data, io.length); + + status = netsec_do_seal(schannel_state, + seq_num_initial.data, + confounder, + io.data, + io.length, + true); + + assert_true(NT_STATUS_IS_OK(status)); + dump_data(0, io.data, io.length); + DEBUG(0,("confounder after crypt:\n")); + dump_data(0, confounder, 8); + dump_data(0, seq_num_initial.data, 8); + assert_memory_equal(io.data, crypt_expected.data, crypt_expected.length); + assert_memory_equal(confounder, confounder_expected.data, confounder_expected.length); + + status = netsec_do_seal(schannel_state, + seq_num_initial.data, + confounder, + io.data, + io.length, + false); + + assert_true(NT_STATUS_IS_OK(status)); + dump_data(0, io.data, io.length); + DEBUG(0,("confounder after decrypt:\n")); + dump_data(0, confounder, 8); + dump_data(0, seq_num_initial.data, 8); + assert_memory_equal(io.data, clear_initial.data, clear_initial.length); + assert_memory_equal(confounder, confounder_initial.data, confounder_initial.length); + + talloc_free(schannel_state); +} + +static void torture_schannel_seal_rc4(void **state) +{ + const uint8_t _session_key[16] = { + 0x14, 0xD5, 0x7F, 0x8D, 0x8E, 0xCF, 0xFB, 0x56, + 0x71, 0x29, 0x9D, 0x9C, 0x2A, 0x75, 0x00, 0xA1 + }; + const DATA_BLOB session_key = data_blob_const(_session_key, 16); + const uint8_t _seq_num_initial[8] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 + }; + const DATA_BLOB seq_num_initial = + data_blob_const(_seq_num_initial, 8); + const uint8_t _confounder_initial[8] = { + 0x1A, 0x5A, 0xE8, 0xC7, 0xBE, 0x4F, 0x1F, 0x07 + }; + const DATA_BLOB confounder_initial = + data_blob_const(_confounder_initial, 8); + const uint8_t _confounder_expected[8] = { + 0x25, 0x4A, 0x9C, 0x15, 0x82, 0x3E, 0x4A, 0x42 + }; + const DATA_BLOB confounder_expected = + data_blob_const(_confounder_expected, 8); + const uint8_t _clear_initial[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71, + 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x40, 0x28, 0x00, 0x78, 0x57, 0x34, 0x12, + 0x34, 0x12, 0xCD, 0xAB, 0xEF, 0x00, 0x01, 0x23, + 0x45, 0x67, 0x89, 0xAB, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11, + 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const DATA_BLOB clear_initial = data_blob_const(_clear_initial, + sizeof(_clear_initial)); + const uint8_t crypt_buffer[] = { + 0x3E, 0x10, 0x74, 0xD2, 0x3C, 0x71, 0x57, 0x45, + 0xB8, 0xAA, 0xCF, 0xE3, 0x84, 0xBE, 0xC4, 0x00, + 0xF4, 0x4D, 0x88, 0x0A, 0x9B, 0xCC, 0x53, 0xFC, + 0x32, 0xAA, 0x8E, 0x4B, 0x0E, 0xDE, 0x5F, 0x7D, + 0x6D, 0x31, 0x4E, 0xAB, 0xE0, 0x7D, 0x37, 0x9D, + 0x3D, 0x16, 0xD8, 0xBA, 0x6A, 0xB0, 0xD0, 0x99, + 0x14, 0x05, 0x37, 0xCF, 0x63, 0xD3, 0xD7, 0x60, + 0x63, 0x3C, 0x03, 0x0A, 0x30, 0xA0, 0x3E, 0xC7, + 0xDA, 0x94, 0x3B, 0x40, 0x63, 0x74, 0xEF, 0xCF, + 0xE5, 0x48, 0x87, 0xE9, 0x6A, 0x5A, 0xC7, 0x61, + 0xF7, 0x09, 0xB7, 0x7C, 0xDE, 0xDB, 0xB0, 0x94, + 0x9B, 0x99, 0xC0, 0xA7, 0x7E, 0x78, 0x09, 0x35, + 0xB4, 0xF4, 0x11, 0xC3, 0xB3, 0x77, 0xB5, 0x77, + 0x25, 0xEE, 0xFD, 0x2F, 0x9A, 0x15, 0x95, 0x27, + 0x08, 0xDA, 0xD0, 0x28, 0xD6, 0x31, 0xB4, 0xB7, + 0x7A, 0x19, 0xBB, 0xF3, 0x78, 0xF8, 0xC2, 0x5B + }; + const DATA_BLOB crypt_expected = data_blob_const(crypt_buffer, + sizeof(crypt_buffer)); + int buffer_sizes[] = { + 0, 1, 3, 7, 8, 9, 15, 16, 17 + }; + int i; + + torture_schannel_seal_flags(state, 0, + session_key, + seq_num_initial, + confounder_initial, + confounder_expected, + clear_initial, + crypt_expected); + + /* repeat the test for varying buffer sizes */ + + for (i = 0; i < ARRAY_SIZE(buffer_sizes); i++) { + DATA_BLOB clear_initial_trunc = + data_blob_const(clear_initial.data, buffer_sizes[i]); + DATA_BLOB crypt_expected_trunc = + data_blob_const(crypt_expected.data, buffer_sizes[i]); + torture_schannel_seal_flags(state, 0, + session_key, + seq_num_initial, + confounder_initial, + confounder_expected, + clear_initial_trunc, + crypt_expected_trunc); + } +} + +static void torture_schannel_seal_aes(void **state) +{ + const uint8_t _session_key[16] = { + 0x8E, 0xE8, 0x27, 0x85, 0x83, 0x41, 0x3C, 0x8D, + 0xC9, 0x54, 0x70, 0x75, 0x8E, 0xC9, 0x69, 0x91 + }; + const DATA_BLOB session_key = data_blob_const(_session_key, 16); + const uint8_t _seq_num_initial[8] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 + }; + const DATA_BLOB seq_num_initial = + data_blob_const(_seq_num_initial, 8); + const uint8_t _confounder_initial[8] = { + 0x6E, 0x09, 0x25, 0x94, 0x01, 0xA0, 0x09, 0x31 + }; + const DATA_BLOB confounder_initial = + data_blob_const(_confounder_initial, 8); + const uint8_t _confounder_expected[8] = { + 0xCA, 0xFB, 0xAC, 0xFB, 0xA8, 0x26, 0x75, 0x2A + }; + const DATA_BLOB confounder_expected = + data_blob_const(_confounder_expected, 8); + const uint8_t _clear_initial[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71, + 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x40, 0x28, 0x00, 0x78, 0x57, 0x34, 0x12, + 0x34, 0x12, 0xCD, 0xAB, 0xEF, 0x00, 0x01, 0x23, + 0x45, 0x67, 0x89, 0xAB, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11, + 0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const DATA_BLOB clear_initial = data_blob_const(_clear_initial, + sizeof(_clear_initial)); + const uint8_t crypt_buffer[] = { + 0xE2, 0xE5, 0xE3, 0x26, 0x45, 0xFB, 0xFC, 0xF3, + 0x9C, 0x14, 0xDD, 0xE1, 0x39, 0x23, 0xE0, 0x55, + 0xED, 0x8F, 0xF4, 0x92, 0xA1, 0xBD, 0xDC, 0x40, + 0x58, 0x6F, 0xD2, 0x5B, 0xF9, 0xC9, 0xA3, 0x87, + 0x46, 0x4B, 0x7F, 0xB2, 0x03, 0xD2, 0x35, 0x22, + 0x3E, 0x70, 0x9F, 0x1E, 0x3F, 0x1F, 0xDB, 0x7D, + 0x79, 0x88, 0x5A, 0x3D, 0xD3, 0x40, 0x1E, 0x69, + 0xD7, 0xE2, 0x1D, 0x5A, 0xE9, 0x3B, 0xE1, 0xE2, + 0x98, 0xFD, 0xCB, 0x3A, 0xF7, 0xB5, 0x1C, 0xF8, + 0xCA, 0x02, 0x00, 0x99, 0x9F, 0x0C, 0x01, 0xE6, + 0xD2, 0x00, 0xAF, 0xE0, 0x51, 0x88, 0x62, 0x50, + 0xB7, 0xE8, 0x6D, 0x63, 0x4B, 0x97, 0x05, 0xC1, + 0xD4, 0x83, 0x96, 0x29, 0x80, 0xAE, 0xD8, 0xA2, + 0xED, 0xC9, 0x5D, 0x0D, 0x29, 0xFF, 0x2C, 0x23, + 0x02, 0xFA, 0x3B, 0xEE, 0xE8, 0xBA, 0x06, 0x01, + 0x95, 0xDF, 0x80, 0x76, 0x0B, 0x17, 0x0E, 0xD8 + }; + const DATA_BLOB crypt_expected = data_blob_const(crypt_buffer, + sizeof(crypt_buffer)); + int buffer_sizes[] = { + 0, 1, 3, 7, 8, 9, 15, 16, 17 + }; + int i; + + torture_schannel_seal_flags(state, NETLOGON_NEG_SUPPORTS_AES, + session_key, + seq_num_initial, + confounder_initial, + confounder_expected, + clear_initial, + crypt_expected); + + /* repeat the test for varying buffer sizes */ + + for (i = 0; i < ARRAY_SIZE(buffer_sizes); i++) { + DATA_BLOB clear_initial_trunc = + data_blob_const(clear_initial.data, buffer_sizes[i]); + DATA_BLOB crypt_expected_trunc = + data_blob_const(crypt_expected.data, buffer_sizes[i]); + torture_schannel_seal_flags(state, NETLOGON_NEG_SUPPORTS_AES, + session_key, + seq_num_initial, + confounder_initial, + confounder_expected, + clear_initial_trunc, + crypt_expected_trunc); + } +} + +int main(int argc, char *argv[]) +{ + int rc; + const struct CMUnitTest tests[] = { + cmocka_unit_test(torture_schannel_seal_rc4), + cmocka_unit_test(torture_schannel_seal_aes), + }; + + if (argc == 2) { + cmocka_set_test_filter(argv[1]); + } + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); + + rc = cmocka_run_group_tests(tests, NULL, NULL); + + return rc; +} diff --git a/libcli/auth/wscript_build b/libcli/auth/wscript_build index 39489c20b4e..04e2b09eadf 100644 --- a/libcli/auth/wscript_build +++ b/libcli/auth/wscript_build @@ -54,3 +54,11 @@ bld.SAMBA_BINARY( ''', install=False ) + +bld.SAMBA_BINARY('test_schannel', + source='tests/test_schannel.c', + deps=''' + gensec + cmocka + ''', + install=False) diff --git a/selftest/knownfail b/selftest/knownfail index 7b54b77a708..94b0f014749 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -374,3 +374,4 @@ ^samba.tests.ntlmdisabled.python\(ktest\).python2.ntlmdisabled.NtlmDisabledTests.test_samr_change_password\(ktest\) ^samba.tests.ntlmdisabled.python\(ad_dc_no_ntlm\).python3.ntlmdisabled.NtlmDisabledTests.test_ntlm_connection\(ad_dc_no_ntlm\) ^samba.tests.ntlmdisabled.python\(ad_dc_no_ntlm\).python2.ntlmdisabled.NtlmDisabledTests.test_ntlm_connection\(ad_dc_no_ntlm\) +^samba.unittests.schannel.torture_schannel_seal_rc4 diff --git a/selftest/tests.py b/selftest/tests.py index e767f276353..bbb5709ee47 100644 --- a/selftest/tests.py +++ b/selftest/tests.py @@ -390,6 +390,8 @@ plantestsuite("samba.unittests.byteorder", "none", [os.path.join(bindir(), "default/lib/util/test_byteorder")]) plantestsuite("samba.unittests.ntlm_check", "none", [os.path.join(bindir(), "default/libcli/auth/test_ntlm_check")]) +plantestsuite("samba.unittests.schannel", "none", + [os.path.join(bindir(), "default/libcli/auth/test_schannel")]) plantestsuite("samba.unittests.test_registry_regfio", "none", [os.path.join(bindir(), "default/source3/test_registry_regfio")]) plantestsuite("samba.unittests.test_oLschema2ldif", "none", -- 2.17.1 From fc0efd56d0584d8ca950ad837bd19e7341833dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Fri, 20 Sep 2019 18:32:43 +0200 Subject: [PATCH 252/376] auth/gensec: fix non-AES schannel seal BUG: https://bugzilla.samba.org/show_bug.cgi?id=14134 Guenther Signed-off-by: Guenther Deschner Reviewed-by: Andreas Schneider (cherry picked from commit 709d54d68a9c2cb3cda91d9ab63228a7adbaceb4) --- auth/gensec/schannel.c | 9 +++++++++ selftest/knownfail | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/auth/gensec/schannel.c b/auth/gensec/schannel.c index 8ba1eafc76d..74a3eb5c690 100644 --- a/auth/gensec/schannel.c +++ b/auth/gensec/schannel.c @@ -296,6 +296,15 @@ static NTSTATUS netsec_do_seal(struct schannel_state *state, ZERO_ARRAY(_sealing_key); return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); } + gnutls_cipher_deinit(cipher_hnd); + rc = gnutls_cipher_init(&cipher_hnd, + GNUTLS_CIPHER_ARCFOUR_128, + &sealing_key, + NULL); + if (rc < 0) { + ZERO_ARRAY(_sealing_key); + return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID); + } rc = gnutls_cipher_encrypt(cipher_hnd, data, length); diff --git a/selftest/knownfail b/selftest/knownfail index 94b0f014749..7b54b77a708 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -374,4 +374,3 @@ ^samba.tests.ntlmdisabled.python\(ktest\).python2.ntlmdisabled.NtlmDisabledTests.test_samr_change_password\(ktest\) ^samba.tests.ntlmdisabled.python\(ad_dc_no_ntlm\).python3.ntlmdisabled.NtlmDisabledTests.test_ntlm_connection\(ad_dc_no_ntlm\) ^samba.tests.ntlmdisabled.python\(ad_dc_no_ntlm\).python2.ntlmdisabled.NtlmDisabledTests.test_ntlm_connection\(ad_dc_no_ntlm\) -^samba.unittests.schannel.torture_schannel_seal_rc4 -- 2.17.1 From f5c8dea0ae75e2d24fd3268e2b5b427cb81225c9 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 23 Sep 2019 15:15:01 -0700 Subject: [PATCH 253/376] torture:smb2: extend test for File-IDs This now hopefully covers most possible combinations of creating and opening files plus, checking the file's File-ID after every operation. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 432202413f4d11d761c62f46a50747fcb9b6f0cf) --- selftest/knownfail.d/samba3.smb2.fileid | 1 + source4/torture/smb2/create.c | 299 ++++++++++++++++++++---- 2 files changed, 259 insertions(+), 41 deletions(-) create mode 100644 selftest/knownfail.d/samba3.smb2.fileid diff --git a/selftest/knownfail.d/samba3.smb2.fileid b/selftest/knownfail.d/samba3.smb2.fileid new file mode 100644 index 00000000000..89455dacdf0 --- /dev/null +++ b/selftest/knownfail.d/samba3.smb2.fileid @@ -0,0 +1 @@ +^samba3.smb2.fileid.fileid\(nt4_dc\) diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index beddefc4c8d..ea83b483491 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -1919,8 +1919,8 @@ static bool test_fileid(struct torture_context *tctx, struct smb2_find f; unsigned int count; union smb_search_data *d; - uint64_t fileid; - uint64_t stream_fileid; + uint64_t expected_fileid; + uint64_t returned_fileid; NTSTATUS status; bool ret = true; @@ -1930,6 +1930,9 @@ static bool test_fileid(struct torture_context *tctx, torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed\n"); + /* + * Initial create with QFID + */ create = (struct smb2_create) { .in.desired_access = SEC_FILE_ALL, .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, @@ -1943,9 +1946,47 @@ static bool test_fileid(struct torture_context *tctx, torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "test file could not be created\n"); h1 = create.out.file.handle; + expected_fileid = BVAL(&create.out.on_disk_id, 0); + + /* + * Getinfo the File-ID on the just opened handle + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Open existing with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = fname, + .in.query_on_disk_id = true, + }; - fileid = BVAL(&create.out.on_disk_id, 0); + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + /* + * Getinfo the File-ID on the just opened handle + */ finfo = (union smb_fileinfo) { .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, .generic.in.file.handle = h1, @@ -1954,33 +1995,111 @@ static bool test_fileid(struct torture_context *tctx, status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Overwrite with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OVERWRITE, + .in.fname = fname, + .in.query_on_disk_id = true, + }; - torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, ret, done, "bad fileid\n"); - f = (struct smb2_find) { - .in.file.handle = testdirh, - .in.pattern = "foo", - .in.max_response_size = 0x1000, - .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + /* + * Getinfo the File-ID on the open with overwrite handle + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, }; - status = smb2_find_level(tree, tree, &f, &count, &d); + status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, - "smb2_find_level failed\n"); + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); - torture_assert_u64_equal_goto(tctx, - d->id_both_directory_info.file_id, - fileid, + /* + * Do some modifications on the basefile (IO, setinfo), verifying + * File-ID after each step. + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = fname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + + status = smb2_util_write(tree, h1, "foo", 0, strlen("foo")); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, ret, done, "bad fileid\n"); + sinfo = (union smb_setfileinfo) { + .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION, + .basic_info.in.file.handle = h1, + }; + unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL)); + + status = smb2_setinfo_file(tree, &sinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + /* + * Create stream, check the stream's File-ID, should be the same as the + * base file (sic!, tested against Windows). + */ create = (struct smb2_create) { .in.desired_access = SEC_FILE_ALL, .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, .in.file_attributes = FILE_ATTRIBUTE_NORMAL, - .in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF, + .in.create_disposition = NTCREATEX_DISP_CREATE, .in.fname = sname, .in.query_on_disk_id = true, }; @@ -1989,11 +2108,13 @@ static bool test_fileid(struct torture_context *tctx, torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "test file could not be created\n"); h1 = create.out.file.handle; - - stream_fileid = BVAL(&create.out.on_disk_id, 0); - torture_assert_u64_equal_goto(tctx, stream_fileid, fileid, + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, ret, done, "bad fileid\n"); + /* + * Getinfo the File-ID on the created stream + */ finfo = (union smb_fileinfo) { .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, .generic.in.file.handle = h1, @@ -2002,31 +2123,118 @@ static bool test_fileid(struct torture_context *tctx, status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Open stream, check the stream's File-ID, should be the same as the + * base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = sname, + .in.query_on_disk_id = true, + }; - torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, ret, done, "bad fileid\n"); - f = (struct smb2_find) { - .in.file.handle = testdirh, - .in.pattern = "foo", - .in.max_response_size = 0x1000, - .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, - .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART, + /* + * Getinfo the File-ID on the opened stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, }; - status = smb2_find_level(tree, tree, &f, &count, &d); + status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, - "smb2_find_level failed\n"); + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); - torture_assert_u64_equal_goto(tctx, - d->id_both_directory_info.file_id, - fileid, + /* + * Overwrite stream, check the stream's File-ID, should be the same as + * the base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OVERWRITE, + .in.fname = sname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, ret, done, "bad fileid\n"); + /* + * Getinfo the File-ID on the overwritten stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Do some modifications on the stream (IO, setinfo), verifying File-ID + * after earch step. + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = sname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + status = smb2_util_write(tree, h1, "foo", 0, strlen("foo")); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_write failed\n"); + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + sinfo = (union smb_setfileinfo) { .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION, .basic_info.in.file.handle = h1, @@ -2041,16 +2249,17 @@ static bool test_fileid(struct torture_context *tctx, .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, .generic.in.file.handle = h1, }; - status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed\n"); - - torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, - ret, done, "bad fileid\n"); - smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + /* + * Final open of the basefile with QFID + */ create = (struct smb2_create) { .in.desired_access = SEC_FILE_ALL, .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, @@ -2064,7 +2273,13 @@ static bool test_fileid(struct torture_context *tctx, torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "test file could not be created\n"); h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + /* + * Final Getinfo checking File-ID + */ finfo = (union smb_fileinfo) { .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, .generic.in.file.handle = h1, @@ -2073,10 +2288,15 @@ static bool test_fileid(struct torture_context *tctx, status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n"); - - torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, ret, done, "bad fileid\n"); + /* + * Final list directory, verifying the operations on basefile and stream + * didn't modify the base file metadata. + */ f = (struct smb2_find) { .in.file.handle = testdirh, .in.pattern = "foo", @@ -2088,14 +2308,11 @@ static bool test_fileid(struct torture_context *tctx, status = smb2_find_level(tree, tree, &f, &count, &d); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_level failed\n"); - torture_assert_u64_equal_goto(tctx, d->id_both_directory_info.file_id, - fileid, + expected_fileid, ret, done, "bad fileid\n"); - smb2_util_close(tree, h1); - done: smb2_util_close(tree, testdirh); smb2_deltree(tree, DNAME); -- 2.17.1 From 2204788e596478d9635f1577ccb7dd76ed66e6a6 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 24 Sep 2019 13:09:03 -0700 Subject: [PATCH 254/376] torture:smb2: add a File-ID test on directories BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 300b47442b023532bd65417fcec04d811f40ef76) --- selftest/knownfail.d/samba3.smb2.fileid | 1 + source4/torture/smb2/create.c | 328 ++++++++++++++++++++++++ 2 files changed, 329 insertions(+) diff --git a/selftest/knownfail.d/samba3.smb2.fileid b/selftest/knownfail.d/samba3.smb2.fileid index 89455dacdf0..bdf86ac61b1 100644 --- a/selftest/knownfail.d/samba3.smb2.fileid +++ b/selftest/knownfail.d/samba3.smb2.fileid @@ -1 +1,2 @@ ^samba3.smb2.fileid.fileid\(nt4_dc\) +^samba3.smb2.fileid.fileid-dir\(nt4_dc\) diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index ea83b483491..aab74f5569a 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -2320,6 +2320,333 @@ done: return ret; } +static bool test_fileid_dir(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *dname = DNAME "\\foo"; + const char *sname = DNAME "\\foo:bar"; + struct smb2_handle testdirh; + struct smb2_handle h1; + struct smb2_create create; + union smb_fileinfo finfo; + union smb_setfileinfo sinfo; + struct smb2_find f; + unsigned int count; + union smb_search_data *d; + uint64_t expected_fileid; + uint64_t returned_fileid; + NTSTATUS status; + bool ret = true; + + smb2_deltree(tree, DNAME); + + status = torture_smb2_testdir(tree, DNAME, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir failed\n"); + + /* + * Initial directory create with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.create_disposition = NTCREATEX_DISP_OPEN_IF, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.fname = dname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + expected_fileid = BVAL(&create.out.on_disk_id, 0); + + /* + * Getinfo the File-ID on the just opened handle + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Open existing directory with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.fname = dname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Getinfo the File-ID on the just opened handle + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Create stream, check the stream's File-ID, should be the same as the + * base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_CREATE, + .in.fname = sname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Getinfo the File-ID on the created stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Open stream, check the stream's File-ID, should be the same as the + * base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = sname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Getinfo the File-ID on the opened stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Overwrite stream, check the stream's File-ID, should be the same as + * the base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OVERWRITE, + .in.fname = sname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Getinfo the File-ID on the overwritten stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Do some modifications on the stream (IO, setinfo), verifying File-ID + * after earch step. + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = sname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + + status = smb2_util_write(tree, h1, "foo", 0, strlen("foo")); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + sinfo = (union smb_setfileinfo) { + .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION, + .basic_info.in.file.handle = h1, + }; + unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL)); + + status = smb2_setinfo_file(tree, &sinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Final open of the directory with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = dname, + .in.query_on_disk_id = true, + }; + + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Final Getinfo checking File-ID + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Final list directory, verifying the operations on basefile and stream + * didn't modify the base file metadata. + */ + f = (struct smb2_find) { + .in.file.handle = testdirh, + .in.pattern = "foo", + .in.max_response_size = 0x1000, + .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART, + }; + + status = smb2_find_level(tree, tree, &f, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_find_level failed\n"); + torture_assert_u64_equal_goto(tctx, + d->id_both_directory_info.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + +done: + smb2_util_close(tree, testdirh); + smb2_deltree(tree, DNAME); + talloc_free(mem_ctx); + return ret; +} + /* basic testing of SMB2 read */ @@ -2366,6 +2693,7 @@ struct torture_suite *torture_smb2_fileid_init(TALLOC_CTX *ctx) struct torture_suite *suite = torture_suite_create(ctx, "fileid"); torture_suite_add_1smb2_test(suite, "fileid", test_fileid); + torture_suite_add_1smb2_test(suite, "fileid-dir", test_fileid_dir); suite->description = talloc_strdup(suite, "SMB2-CREATE tests"); -- 2.17.1 From 459acf2728aa0c3bc935227998cdc59ead5a2e7c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 23 Sep 2019 15:15:31 -0700 Subject: [PATCH 255/376] s3:smbd: change the place where we call dos_mode() when processing SMB2_CREATE This is needed for ordinary file or directory opens so the QFID create context response gets the correct File-ID value via dos_mode() from the DOS attributes xattr. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit e1dfaa2b038d91e43d8d34bf1526b7728dba58a5) --- source3/smbd/smb2_create.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 61ed72169fb..66f4aad8c9e 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -1274,6 +1274,9 @@ static void smbd_smb2_create_after_exec(struct tevent_req *req) DEBUG(10, ("smbd_smb2_create_send: " "response construction phase\n")); + state->out_file_attributes = dos_mode(state->result->conn, + state->result->fsp_name); + if (state->mxac != NULL) { NTTIME last_write_time; @@ -1472,8 +1475,6 @@ static void smbd_smb2_create_finish(struct tevent_req *req) state->out_create_action = state->info; } result->op->create_action = state->out_create_action; - state->out_file_attributes = dos_mode(result->conn, - result->fsp_name); state->out_creation_ts = get_create_timespec(smb1req->conn, result, result->fsp_name); -- 2.17.1 From 2d62bd58db9f7c7e72b35ef1c62660107f06b8c9 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 23 Sep 2019 15:16:58 -0700 Subject: [PATCH 256/376] s3:smbd: when storing DOS attribute call dos_mode() beforehand This is required to ensure File-ID info is populated with the correct on-disk value, before calling file_set_dosmode() which will update the on-disk value. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 49a754b82d33fb523cda4151a865584ae52a2e2f) --- selftest/knownfail.d/samba3.smb2.fileid | 1 - source3/smbd/open.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/selftest/knownfail.d/samba3.smb2.fileid b/selftest/knownfail.d/samba3.smb2.fileid index bdf86ac61b1..89455dacdf0 100644 --- a/selftest/knownfail.d/samba3.smb2.fileid +++ b/selftest/knownfail.d/samba3.smb2.fileid @@ -1,2 +1 @@ ^samba3.smb2.fileid.fileid\(nt4_dc\) -^samba3.smb2.fileid.fileid-dir\(nt4_dc\) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index a5650ac9c2d..7f1f8eae593 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3725,6 +3725,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* Overwritten files should be initially set as archive */ if ((info == FILE_WAS_OVERWRITTEN && lp_map_archive(SNUM(conn))) || lp_store_dos_attributes(SNUM(conn))) { + (void)dos_mode(conn, smb_fname); if (!posix_open) { if (file_set_dosmode(conn, smb_fname, new_dos_attributes | FILE_ATTRIBUTE_ARCHIVE, -- 2.17.1 From 2da0f65cd911e439d4c033f999a7549bc3610714 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 08:53:29 -0700 Subject: [PATCH 257/376] s3:lib: rework a return expression into an if block Needed to add additional stuff after the if block in the next commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit d7dc85990a177954925644f9ff332b3481a03cc7) --- source3/lib/filename_util.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 8a16bacddbe..6bf29c2b0c9 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -253,7 +253,11 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) return false; } - return smb_fname->stream_name != NULL; + if (smb_fname->stream_name == NULL) { + return false; + } + + return true; } /**************************************************************************** -- 2.17.1 From 2ef4d9883f4b11098e8666143192840a3b574b30 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 10:15:27 -0700 Subject: [PATCH 258/376] s3:lib: assert stream_name is NULL for POSIX paths BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 6c1647ca7a2f68825c34e9ccc18b86ef911e14ac) --- source3/lib/filename_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 6bf29c2b0c9..165adb116b5 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -250,7 +250,7 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) } if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) { - return false; + SMB_ASSERT(smb_fname->stream_name == NULL); } if (smb_fname->stream_name == NULL) { -- 2.17.1 From d7a2e7c33907ece55dad26c75b076aba3facc057 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 10:18:03 -0700 Subject: [PATCH 259/376] s3:lib: factor out stream name asserts to helper function BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit f9fdb8a2a6b9ad0fbb89a9734e81a8b1f527966f) --- source3/lib/filename_util.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 165adb116b5..7b3fab90c46 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -239,10 +239,7 @@ struct smb_filename *cp_smb_filename(TALLOC_CTX *mem_ctx, return out; } -/**************************************************************************** - Simple check to determine if the filename is a stream. - ***************************************************************************/ -bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) +static void assert_valid_stream_smb_fname(const struct smb_filename *smb_fname) { /* stream_name must always be NULL if there is no stream. */ if (smb_fname->stream_name) { @@ -252,6 +249,15 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) { SMB_ASSERT(smb_fname->stream_name == NULL); } +} + +/**************************************************************************** + Simple check to determine if the filename is a stream. + ***************************************************************************/ + +bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) +{ + assert_valid_stream_smb_fname(smb_fname); if (smb_fname->stream_name == NULL) { return false; -- 2.17.1 From 23b4938c18a4f51609ca588878f935ef1eb6d9a2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 26 Sep 2019 10:38:06 -0700 Subject: [PATCH 260/376] s3:lib: expand a comment with the function doc for is_ntfs_stream_smb_fname Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 2584b4cdeae3f83962cd11538cd4e441104c8274) --- source3/lib/filename_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 7b3fab90c46..750c0bb8312 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -252,7 +252,8 @@ static void assert_valid_stream_smb_fname(const struct smb_filename *smb_fname) } /**************************************************************************** - Simple check to determine if the filename is a stream. + Simple check to determine if a smb_fname is a real named stream or the + default stream. ***************************************************************************/ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) -- 2.17.1 From 42bc7f28e1a1662f73bce606dbb3b862e399a40d Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 11:19:26 -0700 Subject: [PATCH 261/376] s3:lib: implement logic directly in is_ntfs_default_stream_smb_fname() This allows changing the semantics of is_ntfs_stream_smb_fname() in the next commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 3f8bc1ce3e094f943363921c46803fd5ec9f73bb) --- source3/lib/filename_util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 750c0bb8312..ee49ae5ff8c 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -272,7 +272,9 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) ***************************************************************************/ bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) { - if (!is_ntfs_stream_smb_fname(smb_fname)) { + assert_valid_stream_smb_fname(smb_fname); + + if (smb_fname->stream_name == NULL) { return false; } -- 2.17.1 From c48a5c6b8c995595a519e9069e3efbe24291f190 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 11:29:04 -0700 Subject: [PATCH 262/376] s3:lib: use strequal_m() in is_ntfs_default_stream_smb_fname() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 780a8dcba998471bb154e8bae4391786b793e332) --- source3/lib/filename_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index ee49ae5ff8c..2917481c8bf 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -278,7 +278,7 @@ bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) return false; } - return strcasecmp_m(smb_fname->stream_name, "::$DATA") == 0; + return strequal_m(smb_fname->stream_name, "::$DATA"); } /**************************************************************************** -- 2.17.1 From 8f44a25e2a630a28d908392603eae5987ec4e91e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 26 Sep 2019 10:05:40 -0700 Subject: [PATCH 263/376] s3:lib: add is_named_stream() Add a new utility functions that checks whether a struct smb_filename points to a real named stream, excluding the default stream "::$DATA". foo -> false foo::$DATA -> false foo:bar -> true foo:bar:$DATA -> true BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 091e3fdab61217251de1cf5111f070ff295d1649) --- source3/include/proto.h | 1 + source3/lib/filename_util.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/source3/include/proto.h b/source3/include/proto.h index ad6f3bbf9c3..cb8890d340b 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -985,6 +985,7 @@ struct smb_filename *cp_smb_filename_nostream(TALLOC_CTX *mem_ctx, const struct smb_filename *in); bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname); bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname); +bool is_named_stream(const struct smb_filename *smb_fname); bool is_invalid_windows_ea_name(const char *name); bool ea_list_has_invalid_name(struct ea_list *ea_list); bool split_stream_filename(TALLOC_CTX *ctx, diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 2917481c8bf..66c07001eba 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -267,6 +267,32 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) return true; } +/**************************************************************************** + Simple check to determine if a smb_fname is pointing to a normal file or + a named stream that is not the default stream "::$DATA". + + foo -> false + foo::$DATA -> false + foo:bar -> true + foo:bar:$DATA -> true + + ***************************************************************************/ + +bool is_named_stream(const struct smb_filename *smb_fname) +{ + assert_valid_stream_smb_fname(smb_fname); + + if (smb_fname->stream_name == NULL) { + return false; + } + + if (strequal_m(smb_fname->stream_name, "::$DATA")) { + return false; + } + + return true; +} + /**************************************************************************** Returns true if the filename's stream == "::$DATA" ***************************************************************************/ -- 2.17.1 From f98033600613e1c26d233063a99d2a7f7207a74f Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 24 Sep 2019 12:49:38 -0700 Subject: [PATCH 264/376] s3:smbd: ensure a created stream picks up the File-ID from the basefile BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 90a14c90c4bcede1ef5414e0800aa4c84cbcf1c9) --- selftest/knownfail.d/samba3.smb2.fileid | 1 - source3/smbd/open.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 selftest/knownfail.d/samba3.smb2.fileid diff --git a/selftest/knownfail.d/samba3.smb2.fileid b/selftest/knownfail.d/samba3.smb2.fileid deleted file mode 100644 index 89455dacdf0..00000000000 --- a/selftest/knownfail.d/samba3.smb2.fileid +++ /dev/null @@ -1 +0,0 @@ -^samba3.smb2.fileid.fileid\(nt4_dc\) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 7f1f8eae593..8586b467d2e 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3708,7 +3708,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, fsp->initial_delete_on_close = True; } - if (info == FILE_WAS_CREATED) { + if (info == FILE_WAS_CREATED && !is_named_stream(smb_fname)) { smb_fname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME; if (lp_store_dos_attributes(SNUM(conn)) && -- 2.17.1 From c79e39571910d52cb9336212417f072df82a98b2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 26 Sep 2019 10:41:37 -0700 Subject: [PATCH 265/376] s3:smbd: add a comment explaining the File-ID semantics when a file is created BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit c190f3efa9eb4f633df28074b481ff884b67e65f) --- source3/smbd/open.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 8586b467d2e..5524f80af20 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3708,6 +3708,15 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, fsp->initial_delete_on_close = True; } + /* + * If we created a file and it's not a stream, this is the point where + * we set the itime (aka invented time) that get's stored in the DOS + * attribute xattr. The value is going to be either what the filesystem + * provided or a copy of the creation date. + * + * Either way, we turn the itime into a File-ID, unless the filesystem + * provided one (unlikely). + */ if (info == FILE_WAS_CREATED && !is_named_stream(smb_fname)) { smb_fname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME; -- 2.17.1 From 88abbea50659a00a5881ef80ae885914b446d121 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Thu, 3 Oct 2019 13:09:29 +0300 Subject: [PATCH 266/376] spnego: ignore server mech_types list We should not use the mech list sent by the server in the last 'negotiate' packet in CIFS protocol, as it is not protected and may be subject to downgrade attacks. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14106 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher --- auth/gensec/spnego.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/auth/gensec/spnego.c b/auth/gensec/spnego.c index 0b3fbdce7ac..dc73e324d99 100644 --- a/auth/gensec/spnego.c +++ b/auth/gensec/spnego.c @@ -511,7 +511,11 @@ static NTSTATUS gensec_spnego_client_negTokenInit_start( } n->mech_idx = 0; - n->mech_types = spnego_in->negTokenInit.mechTypes; + + /* Do not use server mech list as it isn't protected. Instead, get all + * supported mechs (excluding SPNEGO). */ + n->mech_types = gensec_security_oids(gensec_security, n, + GENSEC_OID_SPNEGO); if (n->mech_types == NULL) { return NT_STATUS_INVALID_PARAMETER; } @@ -658,13 +662,30 @@ static NTSTATUS gensec_spnego_client_negTokenInit_finish( DATA_BLOB *out) { struct spnego_data spnego_out; - const char *my_mechs[] = {NULL, NULL}; + const char * const *mech_types = NULL; bool ok; - my_mechs[0] = spnego_state->neg_oid; + if (n->mech_types == NULL) { + DBG_WARNING("No mech_types list\n"); + return NT_STATUS_INVALID_PARAMETER; + } + + for (mech_types = n->mech_types; *mech_types != NULL; mech_types++) { + int cmp = strcmp(*mech_types, spnego_state->neg_oid); + + if (cmp == 0) { + break; + } + } + + if (*mech_types == NULL) { + DBG_ERR("Can't find selected sub mechanism in mech_types\n"); + return NT_STATUS_INVALID_PARAMETER; + } + /* compose reply */ spnego_out.type = SPNEGO_NEG_TOKEN_INIT; - spnego_out.negTokenInit.mechTypes = my_mechs; + spnego_out.negTokenInit.mechTypes = mech_types; spnego_out.negTokenInit.reqFlags = data_blob_null; spnego_out.negTokenInit.reqFlagsPadding = 0; spnego_out.negTokenInit.mechListMIC = data_blob_null; @@ -676,7 +697,7 @@ static NTSTATUS gensec_spnego_client_negTokenInit_finish( } ok = spnego_write_mech_types(spnego_state, - my_mechs, + mech_types, &spnego_state->mech_types); if (!ok) { DBG_ERR("failed to write mechTypes\n"); -- 2.17.1 From 5a6fed646c6e8f679bcd2fc285406933f518146e Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Thu, 10 Oct 2019 16:18:21 +0200 Subject: [PATCH 267/376] s3:libsmb: Do not check the SPNEGO neg token for KRB5 The list is not protected and this could be a downgrade attack. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14106 Pair-Programmed-With: Isaac Boukris Reviewed-by: Andreas Schneider Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Reviewed-by: Stefan Metzmacher --- source3/libsmb/cliconnect.c | 50 ------------------------------------- 1 file changed, 50 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 94cec062881..3df35931bb6 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -232,8 +232,6 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, char *canon_principal = NULL; char *canon_realm = NULL; const char *target_hostname = NULL; - const DATA_BLOB *server_blob = NULL; - bool got_kerberos_mechanism = false; enum credentials_use_kerberos krb5_state; bool try_kerberos = false; bool need_kinit = false; @@ -242,48 +240,6 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, bool ok; target_hostname = smbXcli_conn_remote_name(cli->conn); - server_blob = smbXcli_conn_server_gss_blob(cli->conn); - - /* the server might not even do spnego */ - if (server_blob != NULL && server_blob->length != 0) { - char *OIDs[ASN1_MAX_OIDS] = { NULL, }; - size_t i; - - /* - * The server sent us the first part of the SPNEGO exchange in the - * negprot reply. It is WRONG to depend on the principal sent in the - * negprot reply, but right now we do it. If we don't receive one, - * we try to best guess, then fall back to NTLM. - */ - ok = spnego_parse_negTokenInit(frame, - *server_blob, - OIDs, - NULL, - NULL); - if (!ok) { - TALLOC_FREE(frame); - return NT_STATUS_INVALID_PARAMETER; - } - if (OIDs[0] == NULL) { - TALLOC_FREE(frame); - return NT_STATUS_INVALID_PARAMETER; - } - - /* make sure the server understands kerberos */ - for (i = 0; OIDs[i] != NULL; i++) { - if (i == 0) { - DEBUG(3,("got OID=%s\n", OIDs[i])); - } else { - DEBUGADD(3,("got OID=%s\n", OIDs[i])); - } - - if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || - strcmp(OIDs[i], OID_KERBEROS5) == 0) { - got_kerberos_mechanism = true; - break; - } - } - } auth_requested = cli_credentials_authentication_requested(creds); if (auth_requested) { @@ -333,12 +289,6 @@ NTSTATUS cli_session_creds_prepare_krb5(struct cli_state *cli, need_kinit = false; } else if (krb5_state == CRED_MUST_USE_KERBEROS) { need_kinit = try_kerberos; - } else if (!got_kerberos_mechanism) { - /* - * Most likely the server doesn't support - * Kerberos, don't waste time doing a kinit - */ - need_kinit = false; } else { need_kinit = try_kerberos; } -- 2.17.1 From 7e40d859283100791602c2504005f7c99ec86996 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Mon, 7 Oct 2019 23:51:19 +0300 Subject: [PATCH 268/376] selftest: s3: add a test for spnego downgrade from krb5 to ntlm BUG: https://bugzilla.samba.org/show_bug.cgi?id=14106 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher --- selftest/knownfail.d/spnego_downgrade | 1 + selftest/target/Samba3.pm | 9 +++++ source3/script/tests/test_smbd_no_krb5.sh | 46 +++++++++++++++++++++++ source3/selftest/tests.py | 4 ++ 4 files changed, 60 insertions(+) create mode 100644 selftest/knownfail.d/spnego_downgrade create mode 100755 source3/script/tests/test_smbd_no_krb5.sh diff --git a/selftest/knownfail.d/spnego_downgrade b/selftest/knownfail.d/spnego_downgrade new file mode 100644 index 00000000000..494a55fd43d --- /dev/null +++ b/selftest/knownfail.d/spnego_downgrade @@ -0,0 +1 @@ +^samba3.blackbox.smbd_no_krb5.test_spnego_downgrade diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 32bd8698df2..b6bfcef824d 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -1608,6 +1608,7 @@ sub provision($$$$$$$$$) my $dfqconffile="$libdir/dfq.conf"; my $errorinjectconf="$libdir/error_inject.conf"; my $delayinjectconf="$libdir/delay_inject.conf"; + my $globalinjectconf="$libdir/global_inject.conf"; my $nss_wrapper_pl = "$ENV{PERL} $self->{srcdir}/third_party/nss_wrapper/nss_wrapper.pl"; my $nss_wrapper_passwd = "$privatedir/passwd"; @@ -1796,6 +1797,8 @@ sub provision($$$$$$$$$) #it just means we ALLOW one to be configured. allow insecure wide links = yes + include = $globalinjectconf + # Begin extra options $extra_options # End extra options @@ -2331,6 +2334,12 @@ sub provision($$$$$$$$$) } close(DFQCONF); + unless (open(DELAYCONF, ">$globalinjectconf")) { + warn("Unable to open $globalinjectconf"); + return undef; + } + close(DELAYCONF); + ## ## create a test account ## diff --git a/source3/script/tests/test_smbd_no_krb5.sh b/source3/script/tests/test_smbd_no_krb5.sh new file mode 100755 index 00000000000..e9dbb4ae80e --- /dev/null +++ b/source3/script/tests/test_smbd_no_krb5.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +if [ $# -lt 1 ]; then +cat < $global_inject_conf + +# verify that kerberos fails +test_smbclient_expect_failure "smbd_no_krb5" "ls" "//$SERVER/tmp" -k $opt || failed=`expr $failed + 1` + +# verify downgrade to ntlmssp +test_smbclient "test_spnego_downgrade" "ls" "//$SERVER/tmp" $opt || failed=`expr $failed + 1` + +echo '' > $global_inject_conf + +testok $0 $failed diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 5b5a1978988..93c41ef956d 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -751,6 +751,10 @@ plantestsuite("samba3.blackbox.net_tdb", "simpleserver:local", plantestsuite("samba3.blackbox.smbd_error", "simpleserver:local", [os.path.join(samba3srcdir, "script/tests/test_smbd_error.sh")]) +plantestsuite("samba3.blackbox.smbd_no_krb5", "ad_member:local", + [os.path.join(samba3srcdir, "script/tests/test_smbd_no_krb5.sh"), + smbclient3, '$SERVER', "$DC_USERNAME", "$DC_PASSWORD", "$PREFIX"]) + plantestsuite("samba3.blackbox.durable_v2_delay", "simpleserver:local", [os.path.join(samba3srcdir, "script/tests/test_durable_handle_reconnect.sh")]) -- 2.17.1 From 27982255d6454841d3d17c8de3b3d4eac9d84adb Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 4 Sep 2019 16:31:21 +0300 Subject: [PATCH 269/376] spnego: add client option to omit sending an optimistic token BUG: https://bugzilla.samba.org/show_bug.cgi?id=14106 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher --- auth/gensec/spnego.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/auth/gensec/spnego.c b/auth/gensec/spnego.c index dc73e324d99..97472c26837 100644 --- a/auth/gensec/spnego.c +++ b/auth/gensec/spnego.c @@ -136,6 +136,7 @@ struct spnego_state { bool done_mic_check; bool simulate_w2k; + bool no_optimistic; /* * The following is used to implement @@ -187,6 +188,10 @@ static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_securi spnego_state->simulate_w2k = gensec_setting_bool(gensec_security->settings, "spnego", "simulate_w2k", false); + spnego_state->no_optimistic = gensec_setting_bool(gensec_security->settings, + "spnego", + "client_no_optimistic", + false); gensec_security->private_data = spnego_state; return NT_STATUS_OK; @@ -1944,6 +1949,12 @@ static void gensec_spnego_update_pre(struct tevent_req *req) * blob and NT_STATUS_OK. */ state->sub.status = NT_STATUS_OK; + } else if (spnego_state->state_position == SPNEGO_CLIENT_START && + spnego_state->no_optimistic) { + /* + * Skip optimistic token per conf. + */ + state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED; } else { /* * MORE_PROCESSING_REQUIRED => -- 2.17.1 From 425ac58f58c999007f740ca0362269977d1380e4 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 4 Sep 2019 16:39:43 +0300 Subject: [PATCH 270/376] selftest: add tests for no optimistic spnego exchange BUG: https://bugzilla.samba.org/show_bug.cgi?id=14106 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher --- selftest/knownfail.d/spnego_no_optimistic | 1 + source4/selftest/tests.py | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 selftest/knownfail.d/spnego_no_optimistic diff --git a/selftest/knownfail.d/spnego_no_optimistic b/selftest/knownfail.d/spnego_no_optimistic new file mode 100644 index 00000000000..54f51446be0 --- /dev/null +++ b/selftest/knownfail.d/spnego_no_optimistic @@ -0,0 +1 @@ +^samba4.smb.spnego.*.no_optimistic diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 3f55649f217..1772611eb53 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -547,6 +547,10 @@ plansmbtorture4testsuite('base.xcopy', "ad_dc_ntvfs", ['//$NETBIOSNAME/xcopy_sha plansmbtorture4testsuite('base.xcopy', "ad_dc_ntvfs", ['//$NETBIOSNAME/xcopy_share', '-k', 'no', '--signing=required', '-U%'], modname="samba4.smb.signing --signing=required anon") plansmbtorture4testsuite('base.xcopy', "s4member", ['//$NETBIOSNAME/xcopy_share', '-k', 'no', '--signing=no', '-U%'], modname="samba4.smb.signing --signing=no anon") +# Test SPNEGO without issuing an optimistic token +opt='--option=spnego:client_no_optimistic=yes' +plansmbtorture4testsuite('base.xcopy', "ad_dc", ['//$NETBIOSNAME/xcopy_share', '-U$USERNAME%$PASSWORD', opt, '-k', 'no'], modname="samba4.smb.spnego.ntlmssp.no_optimistic") +plansmbtorture4testsuite('base.xcopy', "ad_dc", ['//$NETBIOSNAME/xcopy_share', '-U$USERNAME%$PASSWORD', opt, '-k', 'yes'], modname="samba4.smb.spnego.krb5.no_optimistic") wb_opts_default = ["--option=\"torture:strict mode=no\"", "--option=\"torture:timelimit=1\"", "--option=\"torture:winbindd_separator=/\"", "--option=\"torture:winbindd_netbios_name=$SERVER\"", "--option=\"torture:winbindd_netbios_domain=$DOMAIN\""] -- 2.17.1 From 9c4cb9ba9568e9ba0589f041959e71bb496313dd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 11 Oct 2019 13:23:17 +0200 Subject: [PATCH 271/376] python/tests/gensec: make it possible to add knownfail tests for gensec.update() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14106 Signed-off-by: Stefan Metzmacher Reviewed-by: Andreas Schneider --- python/samba/tests/gensec.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/python/samba/tests/gensec.py b/python/samba/tests/gensec.py index b5ce51de756..c9056ef9681 100644 --- a/python/samba/tests/gensec.py +++ b/python/samba/tests/gensec.py @@ -79,10 +79,16 @@ class GensecTests(samba.tests.TestCase): while True: if not client_finished: print("running client gensec_update") - (client_finished, client_to_server) = self.gensec_client.update(server_to_client) + try: + (client_finished, client_to_server) = self.gensec_client.update(server_to_client) + except samba.NTSTATUSError as nt: + raise AssertionError(nt) if not server_finished: print("running server gensec_update") - (server_finished, server_to_client) = self.gensec_server.update(client_to_server) + try: + (server_finished, server_to_client) = self.gensec_server.update(client_to_server) + except samba.NTSTATUSError as nt: + raise AssertionError(nt) if client_finished and server_finished: break -- 2.17.1 From f3a02fdf780578194d4ad722ebd822a04a2dd886 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Fri, 11 Oct 2019 00:20:16 +0300 Subject: [PATCH 272/376] python/tests/gensec: add spnego downgrade python tests BUG: https://bugzilla.samba.org/show_bug.cgi?id=14106 Pair-Programmed-With: Andreas Schneider Signed-off-by: Isaac Boukris Signed-off-by: Andreas Schneider Reviewed-by: Stefan Metzmacher --- python/samba/tests/gensec.py | 24 +++++++++++++++++++++++- selftest/knownfail.d/samba.tests.gensec | 2 ++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 selftest/knownfail.d/samba.tests.gensec diff --git a/python/samba/tests/gensec.py b/python/samba/tests/gensec.py index c9056ef9681..47bb6c82a01 100644 --- a/python/samba/tests/gensec.py +++ b/python/samba/tests/gensec.py @@ -47,11 +47,17 @@ class GensecTests(samba.tests.TestCase): def test_info_uninitialized(self): self.assertRaises(RuntimeError, self.gensec.session_info) - def _test_update(self, mech, client_mech=None): + def _test_update(self, mech, client_mech=None, client_only_opt=None): """Test GENSEC by doing an exchange with ourselves using GSSAPI against a KDC""" """Start up a client and server GENSEC instance to test things with""" + if client_only_opt: + orig_client_opt = self.lp_ctx.get(client_only_opt) + if not orig_client_opt: + orig_client_opt = '' + self.lp_ctx.set(client_only_opt, "yes") + self.gensec_client = gensec.Security.start_client(self.settings) self.gensec_client.set_credentials(self.get_credentials()) self.gensec_client.want_feature(gensec.FEATURE_SEAL) @@ -60,6 +66,9 @@ class GensecTests(samba.tests.TestCase): else: self.gensec_client.start_mech_by_sasl_name(mech) + if client_only_opt: + self.lp_ctx.set(client_only_opt, "no") + self.gensec_server = gensec.Security.start_server(settings=self.settings, auth_context=auth.AuthContext(lp_ctx=self.lp_ctx)) creds = Credentials() @@ -78,11 +87,15 @@ class GensecTests(samba.tests.TestCase): """Run the actual call loop""" while True: if not client_finished: + if client_only_opt: + self.lp_ctx.set(client_only_opt, "yes") print("running client gensec_update") try: (client_finished, client_to_server) = self.gensec_client.update(server_to_client) except samba.NTSTATUSError as nt: raise AssertionError(nt) + if client_only_opt: + self.lp_ctx.set(client_only_opt, "no") if not server_finished: print("running server gensec_update") try: @@ -93,6 +106,9 @@ class GensecTests(samba.tests.TestCase): if client_finished and server_finished: break + if client_only_opt: + self.lp_ctx.set(client_only_opt, orig_client_opt) + self.assertTrue(server_finished) self.assertTrue(client_finished) @@ -121,6 +137,12 @@ class GensecTests(samba.tests.TestCase): def test_update_spnego(self): self._test_update("GSS-SPNEGO") + def test_update_spnego_downgrade(self): + self._test_update("GSS-SPNEGO", "spnego", "gensec:gssapi_krb5") + + def test_update_no_optimistic_spnego(self): + self._test_update("GSS-SPNEGO", "spnego", "spnego:client_no_optimistic") + def test_update_w2k_spnego_client(self): self.lp_ctx.set("spnego:simulate_w2k", "yes") diff --git a/selftest/knownfail.d/samba.tests.gensec b/selftest/knownfail.d/samba.tests.gensec new file mode 100644 index 00000000000..afc9eba9af5 --- /dev/null +++ b/selftest/knownfail.d/samba.tests.gensec @@ -0,0 +1,2 @@ +^samba.tests.gensec.samba.tests.gensec.GensecTests.test_update_no_optimistic_spnego +^samba.tests.gensec.samba.tests.gensec.GensecTests.test_update_spnego_downgrade -- 2.17.1 From 0d292ca72a389010306e79e7f782783b452cc603 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 4 Sep 2019 17:04:12 +0300 Subject: [PATCH 273/376] spnego: fix server handling of no optimistic exchange BUG: https://bugzilla.samba.org/show_bug.cgi?id=14106 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Reviewed-by: Andrew Bartlett Reviewed-by: Stefan Metzmacher Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Sat Oct 12 15:51:42 UTC 2019 on sn-devel-184 --- auth/gensec/spnego.c | 13 +++++++++++++ selftest/knownfail.d/samba.tests.gensec | 2 -- selftest/knownfail.d/spnego_downgrade | 1 - selftest/knownfail.d/spnego_no_optimistic | 1 - 4 files changed, 13 insertions(+), 4 deletions(-) delete mode 100644 selftest/knownfail.d/samba.tests.gensec delete mode 100644 selftest/knownfail.d/spnego_downgrade delete mode 100644 selftest/knownfail.d/spnego_no_optimistic diff --git a/auth/gensec/spnego.c b/auth/gensec/spnego.c index 97472c26837..ddbe03c5d6b 100644 --- a/auth/gensec/spnego.c +++ b/auth/gensec/spnego.c @@ -1321,6 +1321,10 @@ static NTSTATUS gensec_spnego_server_negTokenInit_step( spnego_state->mic_requested = true; } + if (sub_in.length == 0) { + spnego_state->no_optimistic = true; + } + /* * Note that 'cur_sec' is temporary memory, but * cur_sec->oid points to a const string in the @@ -1955,6 +1959,15 @@ static void gensec_spnego_update_pre(struct tevent_req *req) * Skip optimistic token per conf. */ state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED; + } else if (spnego_state->state_position == SPNEGO_SERVER_START && + state->sub.in.length == 0 && spnego_state->no_optimistic) { + /* + * If we didn't like the mechanism for which the client sent us + * an optimistic token, or if he didn't send any, don't call + * the sub mechanism just yet. + */ + state->sub.status = NT_STATUS_MORE_PROCESSING_REQUIRED; + spnego_state->no_optimistic = false; } else { /* * MORE_PROCESSING_REQUIRED => diff --git a/selftest/knownfail.d/samba.tests.gensec b/selftest/knownfail.d/samba.tests.gensec deleted file mode 100644 index afc9eba9af5..00000000000 --- a/selftest/knownfail.d/samba.tests.gensec +++ /dev/null @@ -1,2 +0,0 @@ -^samba.tests.gensec.samba.tests.gensec.GensecTests.test_update_no_optimistic_spnego -^samba.tests.gensec.samba.tests.gensec.GensecTests.test_update_spnego_downgrade diff --git a/selftest/knownfail.d/spnego_downgrade b/selftest/knownfail.d/spnego_downgrade deleted file mode 100644 index 494a55fd43d..00000000000 --- a/selftest/knownfail.d/spnego_downgrade +++ /dev/null @@ -1 +0,0 @@ -^samba3.blackbox.smbd_no_krb5.test_spnego_downgrade diff --git a/selftest/knownfail.d/spnego_no_optimistic b/selftest/knownfail.d/spnego_no_optimistic deleted file mode 100644 index 54f51446be0..00000000000 --- a/selftest/knownfail.d/spnego_no_optimistic +++ /dev/null @@ -1 +0,0 @@ -^samba4.smb.spnego.*.no_optimistic -- 2.17.1 From c191a37848ba01f503ee5fc5000d4ea1a1474500 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 9 Oct 2019 20:11:03 +0200 Subject: [PATCH 274/376] lib:krb5_wrap: Do not create a temporary file for MEMORY keytabs The autobuild cleanup script fails with: The tree has 3 new uncommitted files!!! git clean -n Would remove MEMORY:tmp_smb_creds_SK98Lv Would remove MEMORY:tmp_smb_creds_kornU6 Would remove MEMORY:tmp_smb_creds_ljR828 Signed-off-by: Andreas Schneider Reviewed-by: Stefan Metzmacher (cherry picked from commit d888655244b4d8ec7a69a042e0ff3c074585b0de) --- lib/krb5_wrap/krb5_samba.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/krb5_wrap/krb5_samba.c b/lib/krb5_wrap/krb5_samba.c index a4e73c64f00..5aceae44eec 100644 --- a/lib/krb5_wrap/krb5_samba.c +++ b/lib/krb5_wrap/krb5_samba.c @@ -2002,26 +2002,23 @@ krb5_error_code smb_krb5_kinit_keyblock_ccache(krb5_context ctx, krb_options); #elif defined(HAVE_KRB5_GET_INIT_CREDS_KEYTAB) { -#define SMB_CREDS_KEYTAB "MEMORY:tmp_smb_creds_XXXXXX" - char tmp_name[sizeof(SMB_CREDS_KEYTAB)]; +#define SMB_CREDS_KEYTAB "MEMORY:tmp_kinit_keyblock_ccache" + char tmp_name[64] = {0}; krb5_keytab_entry entry; krb5_keytab keytab; - int tmpfd; - mode_t mask; + int rc; memset(&entry, 0, sizeof(entry)); entry.principal = principal; *(KRB5_KT_KEY(&entry)) = *keyblock; - memcpy(tmp_name, SMB_CREDS_KEYTAB, sizeof(SMB_CREDS_KEYTAB)); - mask = umask(S_IRWXO | S_IRWXG); - tmpfd = mkstemp(tmp_name); - umask(mask); - if (tmpfd == -1) { - DBG_ERR("Failed to mkstemp %s\n", tmp_name); + rc = snprintf(tmp_name, sizeof(tmp_name), + "%s-%p", + SMB_CREDS_KEYTAB, + &my_creds); + if (rc < 0) { return KRB5_KT_BADNAME; } - close(tmpfd); code = krb5_kt_resolve(ctx, tmp_name, &keytab); if (code) { return code; -- 2.17.1 From 41e658f446adaf4a373ece4fbb1d009a69a293dc Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Wed, 9 Oct 2019 16:32:47 +0200 Subject: [PATCH 275/376] s3:libads: Do not turn on canonicalization flag for MIT Kerberos This partially reverts 303b7e59a286896888ee2473995fc50bb2b5ce5e. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14155 Pair-Programmed-With: Isaac Boukris Signed-off-by: Andreas Schneider Signed-off-by: Isaac Boukris Reviewed-by: Stefan Metzmacher (cherry picked from commit 123584294cfd153acc2d9a5be9d71c395c847a25) --- source3/libads/krb5_setpw.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source3/libads/krb5_setpw.c b/source3/libads/krb5_setpw.c index 67bc2f4640d..028b0dcfa65 100644 --- a/source3/libads/krb5_setpw.c +++ b/source3/libads/krb5_setpw.c @@ -207,7 +207,22 @@ static ADS_STATUS ads_krb5_chg_password(const char *kdc_host, krb5_get_init_creds_opt_set_win2k(context, opts, true); krb5_get_init_creds_opt_set_canonicalize(context, opts, true); #else /* MIT */ +#if 0 + /* + * FIXME + * + * Due to an upstream MIT Kerberos bug, this feature is not + * not working. Affection versions (2019-10-09): <= 1.17 + * + * Reproducer: + * kinit -C aDmInIsTrAtOr@ACME.COM -S kadmin/changepw@ACME.COM + * + * This is NOT a problem if the service is a krbtgt. + * + * https://bugzilla.samba.org/show_bug.cgi?id=14155 + */ krb5_get_init_creds_opt_set_canonicalize(opts, true); +#endif #endif /* MIT */ /* note that heimdal will fill in the local addresses if the addresses -- 2.17.1 From 6902275b6f3c337a4ba5d1fea3f1e0f81fa34a4a Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Tue, 15 Oct 2019 13:52:42 +0300 Subject: [PATCH 276/376] nsswitch: Link stress-nss-libwbclient against pthread BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit d473f1e38c2822746030516269b4d70032cf9b2e) --- nsswitch/wscript_build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nsswitch/wscript_build b/nsswitch/wscript_build index 6acc4a19b9b..861ed2f23bf 100644 --- a/nsswitch/wscript_build +++ b/nsswitch/wscript_build @@ -20,7 +20,7 @@ bld.SAMBA_BINARY('nsstest', if bld.CONFIG_SET('HAVE_PTHREAD'): bld.SAMBA_BINARY('stress-nss-libwbclient', source='stress-nss-libwbclient.c', - deps='wbclient', + deps='wbclient pthread', install=False ) -- 2.17.1 From 7f5334a92c4a378f88c0ee8c5fde46dd087a9dc0 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Tue, 15 Oct 2019 17:01:48 +0300 Subject: [PATCH 277/376] s3:libsmb: Link libsmb against pthread BUG: https://bugzilla.samba.org/show_bug.cgi?id=14140 Signed-off-by: Isaac Boukris Reviewed-by: Andreas Schneider Reviewed-by: Alexander Bokovoy (cherry picked from commit 7259197bf716f8b81dea74beefe6ee3b1239f172) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Wed Oct 16 20:39:04 UTC 2019 on sn-devel-184 --- source3/libsmb/wscript | 1 + 1 file changed, 1 insertion(+) diff --git a/source3/libsmb/wscript b/source3/libsmb/wscript index d9e933e9e9f..febff9df7fc 100644 --- a/source3/libsmb/wscript +++ b/source3/libsmb/wscript @@ -16,6 +16,7 @@ def build(bld): libsmb_xattr.c libsmb_setget.c''', public_deps=''' + pthread talloc smbconf libsmb -- 2.17.1 From ad617f2f2944b25528e947c09fc86dcd2b62cf70 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Fri, 18 Oct 2019 11:02:06 +0200 Subject: [PATCH 278/376] WHATSNEW: Add release notes for Samba 4.11.1. Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index d573bb65819..2e61702b71b 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,3 +1,89 @@ + ============================== + Release Notes for Samba 4.11.1 + October 18, 2019 + ============================== + + +This is the latest stable release of the Samba 4.11 release series. + + +Changes since 4.11.0: +--------------------- + +o Michael Adam + * BUG 14141: getpwnam and getpwuid need to return data for ID_TYPE_BOTH + group. + +o Jeremy Allison + * BUG 14094: smbc_readdirplus() is incompatible with smbc_telldir() and + smbc_lseekdir(). + * BUG 14152: s3: smbclient: Stop an SMB2-connection from blundering into + SMB1-specific calls. + +o Ralph Boehme + * BUG 14137: Fix stale file handle error when using mkstemp on a share. + +o Isaac Boukris + * BUG 14106: Fix spnego fallback from kerberos to ntlmssp in smbd server. + * BUG 14140: Overlinking libreplace against librt and pthread against every + binary or library causes issues. + +o Günther Deschner + * BUG 14130: s3-winbindd: Fix forest trusts with additional trust attributes. + * BUG 14134: auth/gensec: Fix non-AES schannel seal. + +o Amitay Isaacs + * BUG 14147: Deleted records can be resurrected during recovery. + +o Björn Jacke + * BUG 14136: Fix uncaught exception in classicupgrade. + * BUG 14139: fault.c: Improve fault_report message text pointing to our wiki. + +o Bryan Mason + * BUG 14128: s3:client: Use DEVICE_URI, instead of argv[0], for Device URI. + +o Stefan Metzmacher + * BUG 14124: pam_winbind with krb5_auth or wbinfo -K doesn't work for users + of trusted domains/forests. + +o Mathieu Parent + * BUG 14131: Remove 'pod2man' as it is no longer needed. + +o Andreas Schneider + * BUG 13884: Joining Active Directory should not use SAMR to set the + password. + * BUG 14140: Overlinking libreplace against librt and pthread against every + binary or library causes issues. + * BUG 14155: 'kpasswd' fails when built with MIT Kerberos. + +o Martin Schwenke + * BUG 14129: Exit code of ctdb nodestatus should not be influenced by deleted + nodes. + + +####################################### +Reporting bugs & Development Discussion +####################################### + +Please discuss this release on the samba-technical mailing list or by +joining the #samba-technical IRC channel on irc.freenode.net. + +If you do report problems then please try to send high quality +feedback. If you don't provide vital information to help us track down +the problem then you will probably be ignored. All bug reports should +be filed under the "Samba 4.1 and newer" product in the project's Bugzilla +database (https://bugzilla.samba.org/). + + +====================================================================== +== Our Code, Our Bugs, Our Responsibility. +== The Samba Team +====================================================================== + + +Release notes for older releases follow: +---------------------------------------- + ============================== Release Notes for Samba 4.11.0 September 17, 2019 -- 2.17.1 From be4cb417135af09fcf076a92bc8b7e02310a2383 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Fri, 18 Oct 2019 11:02:36 +0200 Subject: [PATCH 279/376] VERSION: Disable GIT_SNAPSHOT for Samba 4.11.1. Signed-off-by: Karolin Seeger --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 137edf08bba..61c76acaef7 100644 --- a/VERSION +++ b/VERSION @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=yes +SAMBA_VERSION_IS_GIT_SNAPSHOT=no ######################################################## # This is for specifying a release nickname # -- 2.17.1 From 7b8309398beab679cd4068da497661ce33616edc Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Fri, 18 Oct 2019 11:03:16 +0200 Subject: [PATCH 280/376] VERSION: Bump version up to 4.11.2... and re-enable GIT_SNAPSHOT. Signed-off-by: Karolin Seeger --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 61c76acaef7..fbc941686eb 100644 --- a/VERSION +++ b/VERSION @@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=11 -SAMBA_VERSION_RELEASE=1 +SAMBA_VERSION_RELEASE=2 ######################################################## # If a official release has a serious bug # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname # -- 2.17.1 From 193d6f5e8cc074370bafa282218e1991506a9edc Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Fri, 18 Oct 2019 11:03:16 +0200 Subject: [PATCH 281/376] VERSION: Bump version up to 4.11.2... and re-enable GIT_SNAPSHOT. Signed-off-by: Karolin Seeger (cherry picked from commit 7b8309398beab679cd4068da497661ce33616edc) --- VERSION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 61c76acaef7..fbc941686eb 100644 --- a/VERSION +++ b/VERSION @@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=11 -SAMBA_VERSION_RELEASE=1 +SAMBA_VERSION_RELEASE=2 ######################################################## # If a official release has a serious bug # @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=no +SAMBA_VERSION_IS_GIT_SNAPSHOT=yes ######################################################## # This is for specifying a release nickname # -- 2.17.1 From 07df3dfa6bf081c3f2ad7777995325d834ad3129 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 5 Aug 2019 13:39:53 -0700 Subject: [PATCH 282/376] CVE-2019-10218 - s3: libsmb: Protect SMB1 client code from evil server returned names. Disconnect with NT_STATUS_INVALID_NETWORK_RESPONSE if so. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14071 Signed-off-by: Jeremy Allison --- source3/libsmb/clilist.c | 75 ++++++++++++++++++++++++++++++++++++++++ source3/libsmb/proto.h | 3 ++ 2 files changed, 78 insertions(+) diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index 5cb1fce4338..4f518339e2b 100644 --- a/source3/libsmb/clilist.c +++ b/source3/libsmb/clilist.c @@ -24,6 +24,66 @@ #include "trans2.h" #include "../libcli/smb/smbXcli_base.h" +/**************************************************************************** + Check if a returned directory name is safe. +****************************************************************************/ + +static NTSTATUS is_bad_name(bool windows_names, const char *name) +{ + const char *bad_name_p = NULL; + + bad_name_p = strchr(name, '/'); + if (bad_name_p != NULL) { + /* + * Windows and POSIX names can't have '/'. + * Server is attacking us. + */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (windows_names) { + bad_name_p = strchr(name, '\\'); + if (bad_name_p != NULL) { + /* + * Windows names can't have '\\'. + * Server is attacking us. + */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + } + return NT_STATUS_OK; +} + +/**************************************************************************** + Check if a returned directory name is safe. Disconnect if server is + sending bad names. +****************************************************************************/ + +NTSTATUS is_bad_finfo_name(const struct cli_state *cli, + const struct file_info *finfo) +{ + NTSTATUS status = NT_STATUS_OK; + bool windows_names = true; + + if (cli->requested_posix_capabilities & CIFS_UNIX_POSIX_PATHNAMES_CAP) { + windows_names = false; + } + if (finfo->name != NULL) { + status = is_bad_name(windows_names, finfo->name); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("bad finfo->name\n"); + return status; + } + } + if (finfo->short_name != NULL) { + status = is_bad_name(windows_names, finfo->short_name); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("bad finfo->short_name\n"); + return status; + } + } + return NT_STATUS_OK; +} + /**************************************************************************** Calculate a safe next_entry_offset. ****************************************************************************/ @@ -492,6 +552,13 @@ static NTSTATUS cli_list_old_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, TALLOC_FREE(finfo); return NT_STATUS_NO_MEMORY; } + + status = is_bad_finfo_name(state->cli, finfo); + if (!NT_STATUS_IS_OK(status)) { + smbXcli_conn_disconnect(state->cli->conn, status); + TALLOC_FREE(finfo); + return status; + } } *pfinfo = finfo; return NT_STATUS_OK; @@ -727,6 +794,14 @@ static void cli_list_trans_done(struct tevent_req *subreq) ff_eos = true; break; } + + status = is_bad_finfo_name(state->cli, finfo); + if (!NT_STATUS_IS_OK(status)) { + smbXcli_conn_disconnect(state->cli->conn, status); + tevent_req_nterror(req, status); + return; + } + if (!state->first && (state->mask[0] != '\0') && strcsequal(finfo->name, state->mask)) { DEBUG(1, ("Error: Looping in FIND_NEXT as name %s has " diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 6a647da58c8..48855d7112c 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -760,6 +760,9 @@ NTSTATUS cli_posix_whoami(struct cli_state *cli, /* The following definitions come from libsmb/clilist.c */ +NTSTATUS is_bad_finfo_name(const struct cli_state *cli, + const struct file_info *finfo); + NTSTATUS cli_list_old(struct cli_state *cli,const char *Mask,uint16_t attribute, NTSTATUS (*fn)(const char *, struct file_info *, const char *, void *), void *state); -- 2.17.1 From 914c985e66adc63d54b3e17dab324f376f84e349 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 6 Aug 2019 12:08:09 -0700 Subject: [PATCH 283/376] CVE-2019-10218 - s3: libsmb: Protect SMB2 client code from evil server returned names. Disconnect with NT_STATUS_INVALID_NETWORK_RESPONSE if so. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14071 Signed-off-by: Jeremy Allison --- source3/libsmb/cli_smb2_fnum.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c index 535beaab841..3fa322c243b 100644 --- a/source3/libsmb/cli_smb2_fnum.c +++ b/source3/libsmb/cli_smb2_fnum.c @@ -1442,6 +1442,13 @@ NTSTATUS cli_smb2_list(struct cli_state *cli, goto fail; } + /* Protect against server attack. */ + status = is_bad_finfo_name(cli, finfo); + if (!NT_STATUS_IS_OK(status)) { + smbXcli_conn_disconnect(cli->conn, status); + goto fail; + } + if (dir_check_ftype((uint32_t)finfo->mode, (uint32_t)attribute)) { /* -- 2.17.1 From e0e8830b88e45e3e954b1e5074cef8c8bf5406a8 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 19 Sep 2019 11:50:01 +1200 Subject: [PATCH 284/376] CVE-2019-14833: Use utf8 characters in the unacceptable password This shows that the "check password script" handling has a bug. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12438 Signed-off-by: Andrew Bartlett --- selftest/knownfail.d/unacceptable-passwords | 1 + selftest/target/Samba4.pm | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 selftest/knownfail.d/unacceptable-passwords diff --git a/selftest/knownfail.d/unacceptable-passwords b/selftest/knownfail.d/unacceptable-passwords new file mode 100644 index 00000000000..75fa2fc32b8 --- /dev/null +++ b/selftest/knownfail.d/unacceptable-passwords @@ -0,0 +1 @@ +^samba.tests.samba_tool.user_check_password_script.samba.tests.samba_tool.user_check_password_script.UserCheckPwdTestCase.test_checkpassword_unacceptable\(chgdcpass:local\) \ No newline at end of file diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 02cdfc18bad..195e9b88044 100755 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -1993,7 +1993,7 @@ sub provision_chgdcpass($$) print "PROVISIONING CHGDCPASS...\n"; # This environment disallows the use of this password # (and also removes the default AD complexity checks) - my $unacceptable_password = "widk3Dsle32jxdBdskldsk55klASKQ"; + my $unacceptable_password = "Paßßword-widk3Dsle32jxdBdskldsk55klASKQ"; my $extra_smb_conf = " check password script = $self->{srcdir}/selftest/checkpassword_arg1.sh ${unacceptable_password} allow dcerpc auth level connect:lsarpc = yes -- 2.17.1 From b3a71bf847e3797582a2c657720726694fe424ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= Date: Tue, 6 Aug 2019 16:32:32 +0200 Subject: [PATCH 285/376] CVE-2019-14833 dsdb: send full password to check password script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit utf8_len represents the number of characters (not bytes) of the password. If the password includes multi-byte characters it is required to write the total number of bytes to the check password script. Otherwise the last bytes of the password string would be ignored. Therefore we rename utf8_len to be clear what it does and does not represent. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12438 Signed-off-by: Björn Baumbach Signed-off-by: Andrew Bartlett --- selftest/knownfail.d/unacceptable-passwords | 1 - source4/dsdb/common/util.c | 30 ++++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) delete mode 100644 selftest/knownfail.d/unacceptable-passwords diff --git a/selftest/knownfail.d/unacceptable-passwords b/selftest/knownfail.d/unacceptable-passwords deleted file mode 100644 index 75fa2fc32b8..00000000000 --- a/selftest/knownfail.d/unacceptable-passwords +++ /dev/null @@ -1 +0,0 @@ -^samba.tests.samba_tool.user_check_password_script.samba.tests.samba_tool.user_check_password_script.UserCheckPwdTestCase.test_checkpassword_unacceptable\(chgdcpass:local\) \ No newline at end of file diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index e521ed09999..3ebec827404 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2036,21 +2036,36 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx, const uint32_t pwdProperties, const uint32_t minPwdLength) { - const char *utf8_pw = (const char *)utf8_blob->data; - size_t utf8_len = strlen_m(utf8_pw); char *password_script = NULL; + const char *utf8_pw = (const char *)utf8_blob->data; + + /* + * This looks strange because it is. + * + * The check for the number of characters in the password + * should clearly not be against the byte length, or else a + * single UTF8 character would count for more than one. + * + * We have chosen to use the number of 16-bit units that the + * password encodes to as the measure of length. This is not + * the same as the number of codepoints, if a password + * contains a character beyond the Basic Multilingual Plane + * (above 65535) it will count for more than one "character". + */ + + size_t password_characters_roughly = strlen_m(utf8_pw); /* checks if the "minPwdLength" property is satisfied */ - if (minPwdLength > utf8_len) { + if (minPwdLength > password_characters_roughly) { return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT; } - /* checks the password complexity */ + /* We might not be asked to check the password complexity */ if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) { return SAMR_VALIDATION_STATUS_SUCCESS; } - if (utf8_len == 0) { + if (password_characters_roughly == 0) { return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH; } @@ -2058,6 +2073,7 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx, if (password_script != NULL && *password_script != '\0') { int check_ret = 0; int error = 0; + ssize_t nwritten = 0; struct tevent_context *event_ctx = NULL; struct tevent_req *req = NULL; int cps_stdin = -1; @@ -2120,7 +2136,9 @@ enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx, cps_stdin = samba_runcmd_export_stdin(req); - if (write(cps_stdin, utf8_pw, utf8_len) != utf8_len) { + nwritten = write(cps_stdin, utf8_blob->data, + utf8_blob->length); + if (nwritten != utf8_blob->length) { close(cps_stdin); cps_stdin = -1; TALLOC_FREE(password_script); -- 2.17.1 From 4087d16945f97479b46a2d5fbfc883f813959fd9 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 15 Oct 2019 16:28:46 +1300 Subject: [PATCH 286/376] CVE-2019-14847 dsdb: Demonstrate the correct interaction of ranged_results style attributes and dirsync Incremental results are provided by a flag on the dirsync control, not by changing the attribute name. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14040 Signed-off-by: Andrew Bartlett --- selftest/knownfail.d/dirsync | 1 + source4/dsdb/tests/python/dirsync.py | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 selftest/knownfail.d/dirsync diff --git a/selftest/knownfail.d/dirsync b/selftest/knownfail.d/dirsync new file mode 100644 index 00000000000..bc49fe0d9bb --- /dev/null +++ b/selftest/knownfail.d/dirsync @@ -0,0 +1 @@ +^samba4.ldap.dirsync.python\(ad_dc_ntvfs\).__main__.ExtendedDirsyncTests.test_dirsync_linkedattributes_range\( \ No newline at end of file diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py index 8b46357c670..78117bc364b 100755 --- a/source4/dsdb/tests/python/dirsync.py +++ b/source4/dsdb/tests/python/dirsync.py @@ -28,6 +28,7 @@ from samba.tests.subunitrun import TestProgram, SubunitOptions import samba.getopt as options import base64 +import ldb from ldb import LdbError, SCOPE_BASE from ldb import Message, MessageElement, Dn from ldb import FLAG_MOD_ADD, FLAG_MOD_DELETE @@ -588,6 +589,31 @@ class SimpleDirsyncTests(DirsyncBaseTests): class ExtendedDirsyncTests(SimpleDirsyncTests): + def test_dirsync_linkedattributes_range(self): + self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) + res = self.ldb_admin.search(self.base_dn, + attrs=["member;range=1-1"], + expression="(name=Administrators)", + controls=["dirsync:1:0:0"]) + + self.assertTrue(len(res) > 0) + self.assertTrue(res[0].get("member;range=1-1") is None) + self.assertTrue(res[0].get("member") is not None) + self.assertTrue(len(res[0].get("member")) > 0) + + def test_dirsync_linkedattributes_range_user(self): + self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) + try: + res = self.ldb_simple.search(self.base_dn, + attrs=["member;range=1-1"], + expression="(name=Administrators)", + controls=["dirsync:1:0:0"]) + except LdbError as e: + (num, _) = e.args + self.assertEquals(num, ldb.ERR_INSUFFICIENT_ACCESS_RIGHTS) + else: + self.fail() + def test_dirsync_linkedattributes(self): flag_incr_linked = 2147483648 self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) -- 2.17.1 From e33b8c5651032b82ffa3631b37ddb93f2bfe3b8d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 15 Oct 2019 15:44:34 +1300 Subject: [PATCH 287/376] CVE-2019-14847 dsdb: Correct behaviour of ranged_results when combined with dirsync BUG: https://bugzilla.samba.org/show_bug.cgi?id=14040 Signed-off-by: Andrew Bartlett --- selftest/knownfail.d/dirsync | 1 - source4/dsdb/samdb/ldb_modules/dirsync.c | 11 ++++---- .../dsdb/samdb/ldb_modules/ranged_results.c | 25 ++++++++++++++++--- 3 files changed, 28 insertions(+), 9 deletions(-) delete mode 100644 selftest/knownfail.d/dirsync diff --git a/selftest/knownfail.d/dirsync b/selftest/knownfail.d/dirsync deleted file mode 100644 index bc49fe0d9bb..00000000000 --- a/selftest/knownfail.d/dirsync +++ /dev/null @@ -1 +0,0 @@ -^samba4.ldap.dirsync.python\(ad_dc_ntvfs\).__main__.ExtendedDirsyncTests.test_dirsync_linkedattributes_range\( \ No newline at end of file diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c index 00f24bd6d59..96cec7774cf 100644 --- a/source4/dsdb/samdb/ldb_modules/dirsync.c +++ b/source4/dsdb/samdb/ldb_modules/dirsync.c @@ -1014,7 +1014,7 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req } /* - * check if there's an extended dn control + * check if there's a dirsync control */ control = ldb_request_get_control(req, LDB_CONTROL_DIRSYNC_OID); if (control == NULL) { @@ -1343,11 +1343,12 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req } /* - * Remove our control from the list of controls + * Mark dirsync control as uncritical (done) + * + * We need this so ranged_results knows how to behave with + * dirsync */ - if (!ldb_save_controls(control, req, NULL)) { - return ldb_operr(ldb); - } + control->critical = false; dsc->schema = dsdb_get_schema(ldb, dsc); /* * At the begining we make the hypothesis that we will return a complete diff --git a/source4/dsdb/samdb/ldb_modules/ranged_results.c b/source4/dsdb/samdb/ldb_modules/ranged_results.c index 13bf3a2d0a9..98438799997 100644 --- a/source4/dsdb/samdb/ldb_modules/ranged_results.c +++ b/source4/dsdb/samdb/ldb_modules/ranged_results.c @@ -35,14 +35,14 @@ struct rr_context { struct ldb_module *module; struct ldb_request *req; + bool dirsync_in_use; }; static struct rr_context *rr_init_context(struct ldb_module *module, struct ldb_request *req) { - struct rr_context *ac; - - ac = talloc_zero(req, struct rr_context); + struct ldb_control *dirsync_control = NULL; + struct rr_context *ac = talloc_zero(req, struct rr_context); if (ac == NULL) { ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory"); return NULL; @@ -51,6 +51,16 @@ static struct rr_context *rr_init_context(struct ldb_module *module, ac->module = module; ac->req = req; + /* + * check if there's a dirsync control (as there is an + * interaction between these modules) + */ + dirsync_control = ldb_request_get_control(req, + LDB_CONTROL_DIRSYNC_OID); + if (dirsync_control != NULL) { + ac->dirsync_in_use = true; + } + return ac; } @@ -82,6 +92,15 @@ static int rr_search_callback(struct ldb_request *req, struct ldb_reply *ares) ares->response, ares->error); } + if (ac->dirsync_in_use) { + /* + * We return full attribute values when mixed with + * dirsync + */ + return ldb_module_send_entry(ac->req, + ares->message, + ares->controls); + } /* LDB_REPLY_ENTRY */ temp_ctx = talloc_new(ac->req); -- 2.17.1 From 3815f9bfda8137f33b5f24e81cc61d1027a01748 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Thu, 24 Oct 2019 10:42:16 +0200 Subject: [PATCH 288/376] WHATSNEW: Add release notes for Samba 4.11.2. * Bug 14071: CVE-2019-10218: Client code can return filenames containing path separators. * Bug 12438: CVE-2019-14833: Samba AD DC check password script does not receive the full password. * Bug 14040: CVE-2019-14847: User with "get changes" permission can crash AD DC LDAP server via dirsync. Signed-off-by: Karolin Seeger --- WHATSNEW.txt | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 2e61702b71b..8c6db3b3034 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,3 +1,77 @@ + ============================== + Release Notes for Samba 4.11.2 + October 29, 2019 + ============================== + + +This is a security release in order to address the following defects: + +o CVE-2019-10218: Client code can return filenames containing path separators. +o CVE-2019-14833: Samba AD DC check password script does not receive the full + password. +o CVE-2019-14847: User with "get changes" permission can crash AD DC LDAP server + via dirsync. + +======= +Details +======= + +o CVE-2019-10218: + Malicious servers can cause Samba client code to return filenames containing + path separators to calling code. + +o CVE-2019-14833: + When the password contains multi-byte (non-ASCII) characters, the check + password script does not receive the full password string. + +o CVE-2019-14847: + Users with the "get changes" extended access right can crash the AD DC LDAP + server by requesting an attribute using the range= syntax. + +For more details and workarounds, please refer to the security advisories. + + +Changes since 4.11.1: +--------------------- + +o Jeremy Allison + * BUG 14071: CVE-2019-10218 - s3: libsmb: Protect SMB1 and SMB2 client code + from evil server returned names. + +o Andrew Bartlett + * BUG 12438: CVE-2019-14833: Use utf8 characters in the unacceptable + password. + * BUG 14040: CVE-2019-14847 dsdb: Correct behaviour of ranged_results when + combined with dirsync. + +o Björn Baumbach + * BUG 12438: CVE-2019-14833 dsdb: Send full password to check password + script. + + +####################################### +Reporting bugs & Development Discussion +####################################### + +Please discuss this release on the samba-technical mailing list or by +joining the #samba-technical IRC channel on irc.freenode.net. + +If you do report problems then please try to send high quality +feedback. If you don't provide vital information to help us track down +the problem then you will probably be ignored. All bug reports should +be filed under the "Samba 4.1 and newer" product in the project's Bugzilla +database (https://bugzilla.samba.org/). + + +====================================================================== +== Our Code, Our Bugs, Our Responsibility. +== The Samba Team +====================================================================== + + +Release notes for older releases follow: +---------------------------------------- + ============================== Release Notes for Samba 4.11.1 October 18, 2019 @@ -81,8 +155,8 @@ database (https://bugzilla.samba.org/). ====================================================================== -Release notes for older releases follow: ----------------------------------------- +---------------------------------------------------------------------- + ============================== Release Notes for Samba 4.11.0 -- 2.17.1 From df2b97d12e6d5d36dc152896a21ba44bc7531654 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Thu, 24 Oct 2019 10:52:52 +0200 Subject: [PATCH 289/376] VERSION: Disable GIT_SNAPSHOT for the 4.11.2 release. * Bug 14071: CVE-2019-10218: Client code can return filenames containing path separators. * Bug 12438: CVE-2019-14833: Samba AD DC check password script does not receive the full password. * Bug 14040: CVE-2019-14847: User with "get changes" permission can crash AD DC LDAP server via dirsync. Signed-off-by: Karolin Seeger --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index fbc941686eb..e4636c3dc96 100644 --- a/VERSION +++ b/VERSION @@ -99,7 +99,7 @@ SAMBA_VERSION_RC_RELEASE= # e.g. SAMBA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "3.0.0-SVN-build-199" # ######################################################## -SAMBA_VERSION_IS_GIT_SNAPSHOT=yes +SAMBA_VERSION_IS_GIT_SNAPSHOT=no ######################################################## # This is for specifying a release nickname # -- 2.17.1 From e704eee3083658f7dcdd4238295f8e0b229a1688 Mon Sep 17 00:00:00 2001 From: Karolin Seeger Date: Tue, 29 Oct 2019 11:10:52 +0100 Subject: [PATCH 290/376] VERSION: Bump version up to 4.11.3. Signed-off-by: Karolin Seeger --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index fbc941686eb..e9cc49c7f77 100644 --- a/VERSION +++ b/VERSION @@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=11 -SAMBA_VERSION_RELEASE=2 +SAMBA_VERSION_RELEASE=3 ######################################################## # If a official release has a serious bug # -- 2.17.1 From 509f11547f3eee151e16f14a17c58d193cf81993 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 17 Oct 2019 11:39:02 -0700 Subject: [PATCH 291/376] s3: libsmb: Ensure SMB1 cli_qpathinfo2() doesn't return an inode number. The info level it uses doesn't return that, previously we were using the field that is returned as the EA size as the inode number (which is usually zero, so the code in libsmbclient would then synthesize an inode number from a hash of the pathname, which is all it can do for SMB1). BUG: https://bugzilla.samba.org/show_bug.cgi?id=14161 Signed-off-by: Jeremy Allison Reviewed-by: Andreas Schneider (cherry picked from commit d495074ee27a5f528d5156a69800ee58d799b1eb) --- source3/libsmb/clirap.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index e80dfc92a77..b4b40ebdab4 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -855,7 +855,15 @@ NTSTATUS cli_qpathinfo2_recv(struct tevent_req *req, *size = IVAL2_TO_SMB_BIG_UINT(state->data,48); } if (ino) { - *ino = IVAL(state->data, 64); + /* + * SMB1 qpathinfo2 uses SMB_QUERY_FILE_ALL_INFO + * which doesn't return an inode number (fileid). + * We can't change this to one of the FILE_ID + * info levels as only Win2003 and above support + * these [MS-SMB: 2.2.2.3.1] and the SMB1 code + * needs to support older servers. + */ + *ino = 0; } return NT_STATUS_OK; } -- 2.17.1 From 4aa37b8e722d0ee7c7417b33ea62e7a66151a867 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 17 Oct 2019 12:41:08 -0700 Subject: [PATCH 292/376] s3: torture: Ensure SMB1 cli_qpathinfo2() doesn't return an inode number. Piggyback on existing tests, ensure we don't regress on: BUG: https://bugzilla.samba.org/show_bug.cgi?id=14161 Signed-off-by: Jeremy Allison Reviewed-by: Andreas Schneider (cherry picked from commit 8e55a8562951924e4b1aad5a6d67fc8b309590c1) --- source3/torture/torture.c | 49 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 66dc0cf4d1c..a795e61125f 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -4211,6 +4211,7 @@ static bool run_trans2test(int dummy) bool correct = True; NTSTATUS status; uint32_t fs_attr; + uint64_t ino; printf("starting trans2 test\n"); @@ -4218,6 +4219,14 @@ static bool run_trans2test(int dummy) return False; } + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + /* Ensure ino is zero, SMB2 gets a real one. */ + ino = 0; + } else { + /* Ensure ino is -1, SMB1 never gets a real one. */ + ino = (uint64_t)-1; + } + status = cli_get_fs_attr_info(cli, &fs_attr); if (!NT_STATUS_IS_OK(status)) { printf("ERROR: cli_get_fs_attr_info returned %s\n", @@ -4289,7 +4298,7 @@ static bool run_trans2test(int dummy) O_RDWR | O_CREAT | O_TRUNC, DENY_NONE, &fnum); cli_close(cli, fnum); status = cli_qpathinfo2(cli, fname, &c_time_ts, &a_time_ts, &w_time_ts, - &m_time_ts, &size, NULL, NULL); + &m_time_ts, &size, NULL, &ino); if (!NT_STATUS_IS_OK(status)) { printf("ERROR: qpathinfo2 failed (%s)\n", nt_errstr(status)); correct = False; @@ -4299,6 +4308,19 @@ static bool run_trans2test(int dummy) printf("This system appears to set a initial 0 write time\n"); correct = False; } + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + /* SMB2 should always return an inode. */ + if (ino == 0) { + printf("SMB2 bad inode (0)\n"); + correct = false; + } + } else { + /* SMB1 must always return zero here. */ + if (ino != 0) { + printf("SMB1 bad inode (!0)\n"); + correct = false; + } + } } cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); @@ -11593,11 +11615,20 @@ static bool run_dir_createtime(int dummy) struct timespec create_time1; uint16_t fnum; bool ret = false; + uint64_t ino; if (!torture_open_connection(&cli, 0)) { return false; } + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + /* Ensure ino is zero, SMB2 gets a real one. */ + ino = 0; + } else { + /* Ensure ino is -1, SMB1 never gets a real one. */ + ino = (uint64_t)-1; + } + cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); cli_rmdir(cli, dname); @@ -11608,13 +11639,27 @@ static bool run_dir_createtime(int dummy) } status = cli_qpathinfo2(cli, dname, &create_time, NULL, NULL, NULL, - NULL, NULL, NULL); + NULL, NULL, &ino); if (!NT_STATUS_IS_OK(status)) { printf("cli_qpathinfo2 returned %s\n", nt_errstr(status)); goto out; } + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + /* SMB2 should always return an inode. */ + if (ino == 0) { + printf("SMB2 bad inode (0)\n"); + goto out; + } + } else { + /* SMB1 must always return zero here. */ + if (ino != 0) { + printf("SMB1 bad inode (!0)\n"); + goto out; + } + } + /* Sleep 3 seconds, then create a file. */ sleep(3); -- 2.17.1 From 2958016c30a8d9f80a45b64e91a20d8ebf995d85 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 21 Oct 2019 17:08:08 +0200 Subject: [PATCH 293/376] replace: Only link libnsl and libsocket if requrired BUG: https://bugzilla.samba.org/show_bug.cgi?id=14168 Signed-off-by: Andreas Schneider Reviewed-by: Alexander Bokovoy Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Wed Oct 23 08:23:13 UTC 2019 on sn-devel-184 (cherry picked from commit 263bec1b8d0744da73dd92e4a361fb7430289ab3) Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Mon Nov 4 09:31:23 UTC 2019 on sn-devel-184 --- lib/replace/wscript | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/lib/replace/wscript b/lib/replace/wscript index 240d730cbee..56e2a22de49 100644 --- a/lib/replace/wscript +++ b/lib/replace/wscript @@ -190,10 +190,35 @@ def configure(conf): conf.CHECK_TYPE_IN('sig_atomic_t', 'signal.h', define='HAVE_SIG_ATOMIC_T_TYPE') conf.CHECK_FUNCS('sigsetmask siggetmask sigprocmask sigblock sigaction sigset') - conf.CHECK_FUNCS_IN('''inet_ntoa inet_aton inet_ntop inet_pton connect gethostbyname - getaddrinfo getnameinfo freeaddrinfo gai_strerror socketpair''', - 'socket nsl', checklibc=True, - headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h') + # Those functions are normally available in libc + if not conf.CHECK_FUNCS(''' + inet_ntoa + inet_aton + inet_ntop + inet_pton + connect + gethostbyname + getaddrinfo + getnameinfo + freeaddrinfo + gai_strerror + socketpair''', + headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h'): + conf.CHECK_FUNCS_IN(''' + inet_ntoa + inet_aton + inet_ntop + inet_pton + connect + gethostbyname + getaddrinfo + getnameinfo + freeaddrinfo + gai_strerror + socketpair''', + 'socket nsl', + headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h') + conf.DEFINE('REPLACE_REQUIRES_LIBSOCKET_LIBNSL', 1) conf.CHECK_FUNCS('memset_s memset_explicit') @@ -836,6 +861,7 @@ def build(bld): extra_libs = '' if bld.CONFIG_SET('HAVE_LIBBSD'): extra_libs += ' bsd' if bld.CONFIG_SET('HAVE_LIBRT'): extra_libs += ' rt' + if bld.CONFIG_SET('REPLACE_REQUIRES_LIBSOCKET_LIBNSL'): extra_libs += ' socket nsl' bld.SAMBA_SUBSYSTEM('LIBREPLACE_HOSTCC', REPLACE_HOSTCC_SOURCE, @@ -876,7 +902,7 @@ def build(bld): # at the moment: # hide_symbols=bld.BUILTIN_LIBRARY('replace'), private_library=True, - deps='crypt dl nsl socket attr' + extra_libs) + deps='crypt dl attr' + extra_libs) replace_test_cflags = '' if bld.CONFIG_SET('HAVE_WNO_FORMAT_TRUNCATION'): -- 2.17.1 From b62705398d13bdad54e5abb65a23fa0d94c3571d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 22 Oct 2019 12:12:32 +0200 Subject: [PATCH 294/376] s4:tests/dirsync: add tests for dirsync with extended_dn This demonstrates a problems that the extended_dn returned by the dirsync module always uses the SDDL format for GUID/SID components. Azure AD connect reports discovery errors: reference-value-not-ldap-conformant for attributes member and manager. The key is that it sends the LDAP_SERVER_EXTENDED_DN_OID without an ExtendedDNRequestValue blob, which means the flag value should be treated as 0 and the HEX string format should be used. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14153 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett (cherry picked from commit 6d43d82b49c8cd47da2f1489fe8b52d5a873a19c) --- selftest/knownfail.d/dirsync_extended_dn | 1 + source4/dsdb/tests/python/dirsync.py | 31 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 selftest/knownfail.d/dirsync_extended_dn diff --git a/selftest/knownfail.d/dirsync_extended_dn b/selftest/knownfail.d/dirsync_extended_dn new file mode 100644 index 00000000000..0ef6ea56391 --- /dev/null +++ b/selftest/knownfail.d/dirsync_extended_dn @@ -0,0 +1 @@ +^samba4.ldap.dirsync.python.*.__main__.ExtendedDirsyncTests.test_dirsync_extended_dn diff --git a/source4/dsdb/tests/python/dirsync.py b/source4/dsdb/tests/python/dirsync.py index 78117bc364b..0a22ac4239a 100755 --- a/source4/dsdb/tests/python/dirsync.py +++ b/source4/dsdb/tests/python/dirsync.py @@ -681,6 +681,37 @@ class ExtendedDirsyncTests(SimpleDirsyncTests): self.assertEqual(res[0].get("member;range=1-1"), None) self.assertEqual(len(res[0].get("member;range=0-0")), 2) + def test_dirsync_extended_dn(self): + """Check that dirsync works together with the extended_dn control""" + # Let's search for members + self.ldb_simple = self.get_ldb_connection(self.simple_user, self.user_pass) + res = self.ldb_simple.search(self.base_dn, + expression="(name=Administrators)", + controls=["dirsync:1:1:1"]) + + self.assertTrue(len(res[0].get("member")) > 0) + size = len(res[0].get("member")) + + resEX1 = self.ldb_simple.search(self.base_dn, + expression="(name=Administrators)", + controls=["dirsync:1:1:1","extended_dn:1:1"]) + self.assertTrue(len(resEX1[0].get("member")) > 0) + sizeEX1 = len(resEX1[0].get("member")) + self.assertEqual(sizeEX1, size) + self.assertIn(res[0]["member"][0], resEX1[0]["member"][0]) + self.assertIn(b"; 0) + sizeEX0 = len(resEX0[0].get("member")) + self.assertEqual(sizeEX0, size) + self.assertIn(res[0]["member"][0], resEX0[0]["member"][0]) + self.assertIn(b"; Date: Fri, 4 Oct 2019 14:57:40 +0200 Subject: [PATCH 295/376] s4:dirsync: fix interaction of dirsync and extended_dn controls Azure AD connect reports discovery errors: reference-value-not-ldap-conformant for attributes member and manager. The key is that it sends the LDAP_SERVER_EXTENDED_DN_OID without an ExtendedDNRequestValue blob, which means the flag value should be treated as 0 and the HEX string format should be used. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14153 RN: Prevent azure ad connect from reporting discovery errors: reference-value-not-ldap-conformant Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Thu Oct 24 11:06:58 UTC 2019 on sn-devel-184 (cherry picked from commit d0f566c4ad32d69a1cf896e2dde56fc2489bb7fc) --- selftest/knownfail.d/dirsync_extended_dn | 1 - source4/dsdb/samdb/ldb_modules/dirsync.c | 19 +++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) delete mode 100644 selftest/knownfail.d/dirsync_extended_dn diff --git a/selftest/knownfail.d/dirsync_extended_dn b/selftest/knownfail.d/dirsync_extended_dn deleted file mode 100644 index 0ef6ea56391..00000000000 --- a/selftest/knownfail.d/dirsync_extended_dn +++ /dev/null @@ -1 +0,0 @@ -^samba4.ldap.dirsync.python.*.__main__.ExtendedDirsyncTests.test_dirsync_extended_dn diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c index 96cec7774cf..dfa72a1d203 100644 --- a/source4/dsdb/samdb/ldb_modules/dirsync.c +++ b/source4/dsdb/samdb/ldb_modules/dirsync.c @@ -51,6 +51,7 @@ struct dirsync_context { uint64_t fromreqUSN; uint32_t cursor_size; bool noextended; + int extended_type; bool linkIncrVal; bool localonly; bool partial; @@ -481,7 +482,8 @@ skip: } ldb_dn_extended_filter(dn->dn, myaccept); - dn_ln = ldb_dn_get_extended_linearized(dn, dn->dn, 1); + dn_ln = dsdb_dn_get_extended_linearized(dn, dn, + dsc->extended_type); if (dn_ln == NULL) { talloc_free(dn); @@ -998,6 +1000,7 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req struct ldb_control *control; struct ldb_result *acl_res; struct ldb_dirsync_control *dirsync_ctl; + struct ldb_control *extended = NULL; struct ldb_request *down_req; struct dirsync_context *dsc; struct ldb_context *ldb; @@ -1229,7 +1232,19 @@ static int dirsync_ldb_search(struct ldb_module *module, struct ldb_request *req dsc->nbDefaultAttrs = 3; } - if (!ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID)) { + /* check if there's an extended dn control */ + extended = ldb_request_get_control(req, LDB_CONTROL_EXTENDED_DN_OID); + if (extended != NULL) { + struct ldb_extended_dn_control *extended_ctrl = NULL; + + if (extended->data != NULL) { + extended_ctrl = talloc_get_type(extended->data, + struct ldb_extended_dn_control); + } + if (extended_ctrl != NULL) { + dsc->extended_type = extended_ctrl->type; + } + } else { ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, false, NULL); if (ret != LDB_SUCCESS) { return ret; -- 2.17.1 From 0b3503a436a37a3e67eed7ce66351a172005c57a Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Fri, 30 Aug 2019 00:22:15 +0300 Subject: [PATCH 296/376] libnet_join: build dnsHostName from netbios name and lp_dnsdomain() This make the join process much more reliable, and avoids "Constraint violation" error when the fqdn returned from getaddrinfo has already got assigned an SPN. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14116 Signed-off-by: Isaac Boukris Reviewed-by: Ralph Boehme Reviewed-by: Alexander Bokovoy --- source3/libnet/libnet_join.c | 31 +++++++++++------------------- testprogs/blackbox/test_net_ads.sh | 7 +++++-- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index 1052afde641..ff464ad6e62 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -533,29 +533,23 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, } } - if (!name_to_fqdn(my_fqdn, r->in.machine_name) - || (strchr(my_fqdn, '.') == NULL)) { - fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name, - r->out.dns_domain_name); - } + fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name, lp_dnsdomain()); if (!strlower_m(my_fqdn)) { return ADS_ERROR_LDAP(LDAP_NO_MEMORY); } - if (!strequal(my_fqdn, r->in.machine_name)) { - spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn); - if (!spn) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); - } + spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn); + if (spn == NULL) { + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + } - ok = ads_element_in_array(spn_array, num_spns, spn); + ok = ads_element_in_array(spn_array, num_spns, spn); + if (!ok) { + ok = add_string_to_array(spn_array, spn, + &spn_array, &num_spns); if (!ok) { - ok = add_string_to_array(spn_array, spn, - &spn_array, &num_spns); - if (!ok) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); - } + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); } } @@ -591,12 +585,9 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, /* * Add HOST/netbiosname.domainname */ - if (r->out.dns_domain_name == NULL) { - continue; - } fstr_sprintf(my_fqdn, "%s.%s", *netbios_aliases, - r->out.dns_domain_name); + lp_dnsdomain()); spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn); if (spn == NULL) { diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh index cc8345c4624..ef6f99ddea4 100755 --- a/testprogs/blackbox/test_net_ads.sh +++ b/testprogs/blackbox/test_net_ads.sh @@ -81,7 +81,7 @@ testit "testjoin (dedicated keytab)" $VALGRIND $net_tool ads testjoin -kP || fai netbios=$(grep "netbios name" $BASEDIR/$WORKDIR/client.conf | cut -f2 -d= | awk '{$1=$1};1') uc_netbios=$(echo $netbios | tr '[:lower:]' '[:upper:]') lc_realm=$(echo $REALM | tr '[:upper:]' '[:lower:]') -fqdns="$netbios.$lc_realm" +fqdn="$netbios.$lc_realm" krb_princ="primary/instance@$REALM" testit "test (dedicated keytab) add a fully qualified krb5 principal" $VALGRIND $net_tool ads keytab add $krb_princ -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` @@ -99,7 +99,7 @@ testit "test (dedicated keytab) at least one krb5 principal created from $machin service="nfs" testit "test (dedicated keytab) add a $service service to keytab" $VALGRIND $net_tool ads keytab add $service -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" || failed=`expr $failed + 1` -search_str="$service/$fqdns@$REALM" +search_str="$service/$fqdn@$REALM" found=`$net_tool ads keytab list -U$DC_USERNAME%$DC_PASSWORD --option="kerberosmethod=dedicatedkeytab" --option="dedicatedkeytabfile=$dedicated_keytab_file" | grep $search_str | wc -l` testit "test (dedicated keytab) at least one (long form) krb5 principal created from service added is present in keytab" test $found -gt 1 || failed=`expr $failed + 1` @@ -206,6 +206,9 @@ testit "join" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD || failed testit "testjoin" $VALGRIND $net_tool ads testjoin || failed=`expr $failed + 1` +testit_grep "check dNSHostName" $fqdn $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ dNSHostName || failed=`expr $failed + 1` +testit_grep "check SPN" ${uc_netbios}.${lc_realm} $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1` + ##Goodbye... testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` -- 2.17.1 From 2e7683c937e05085770e88cf48288f0404c28092 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 18 Sep 2019 20:00:34 +0300 Subject: [PATCH 297/376] libnet_join_set_machine_spn: improve style and make a bit room for indentation BUG: https://bugzilla.samba.org/show_bug.cgi?id=14116 Signed-off-by: Isaac Boukris Reviewed-by: Ralph Boehme Reviewed-by: Alexander Bokovoy --- source3/libnet/libnet_join.c | 95 ++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index ff464ad6e62..54bff06c614 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -517,7 +517,7 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, /* Windows only creates HOST/shortname & HOST/fqdn. */ spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name); - if (!spn) { + if (spn == NULL) { return ADS_ERROR_LDAP(LDAP_NO_MEMORY); } if (!strupper_m(spn)) { @@ -553,60 +553,59 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, } } - netbios_aliases = lp_netbios_aliases(); - if (netbios_aliases != NULL) { - for (; *netbios_aliases != NULL; netbios_aliases++) { - /* - * Add HOST/NETBIOSNAME - */ - spn = talloc_asprintf(mem_ctx, "HOST/%s", *netbios_aliases); - if (spn == NULL) { - TALLOC_FREE(spn); - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); - } - if (!strupper_m(spn)) { - TALLOC_FREE(spn); - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); - } + for (netbios_aliases = lp_netbios_aliases(); + netbios_aliases != NULL && *netbios_aliases != NULL; + netbios_aliases++) { + /* + * Add HOST/NETBIOSNAME + */ + spn = talloc_asprintf(mem_ctx, "HOST/%s", *netbios_aliases); + if (spn == NULL) { + TALLOC_FREE(spn); + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + } + if (!strupper_m(spn)) { + TALLOC_FREE(spn); + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + } - ok = ads_element_in_array(spn_array, num_spns, spn); - if (ok) { - TALLOC_FREE(spn); - continue; - } - ok = add_string_to_array(spn_array, spn, - &spn_array, &num_spns); - if (!ok) { - TALLOC_FREE(spn); - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); - } + ok = ads_element_in_array(spn_array, num_spns, spn); + if (ok) { + TALLOC_FREE(spn); + continue; + } + ok = add_string_to_array(spn_array, spn, + &spn_array, &num_spns); + if (!ok) { TALLOC_FREE(spn); + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + } + TALLOC_FREE(spn); - /* - * Add HOST/netbiosname.domainname - */ - fstr_sprintf(my_fqdn, "%s.%s", - *netbios_aliases, - lp_dnsdomain()); + /* + * Add HOST/netbiosname.domainname + */ + fstr_sprintf(my_fqdn, "%s.%s", + *netbios_aliases, + lp_dnsdomain()); - spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn); - if (spn == NULL) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); - } + spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn); + if (spn == NULL) { + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + } - ok = ads_element_in_array(spn_array, num_spns, spn); - if (ok) { - TALLOC_FREE(spn); - continue; - } - ok = add_string_to_array(spn_array, spn, - &spn_array, &num_spns); - if (!ok) { - TALLOC_FREE(spn); - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); - } + ok = ads_element_in_array(spn_array, num_spns, spn); + if (ok) { + TALLOC_FREE(spn); + continue; + } + ok = add_string_to_array(spn_array, spn, + &spn_array, &num_spns); + if (!ok) { TALLOC_FREE(spn); + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); } + TALLOC_FREE(spn); } /* make sure to NULL terminate the array */ -- 2.17.1 From 3f9a9b95dd1f128817a979e8687b480d6dc9cab1 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 18 Sep 2019 21:29:47 +0300 Subject: [PATCH 298/376] libnet_join_set_machine_spn: simplify memory handling and avoid a possible memory leak when passing null to add_string_to_array() as mem_ctx. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14116 Signed-off-by: Isaac Boukris Reviewed-by: Ralph Boehme Reviewed-by: Alexander Bokovoy --- source3/libnet/libnet_join.c | 74 ++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index 54bff06c614..15659b5ab43 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -490,6 +490,7 @@ static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx, static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, struct libnet_JoinCtx *r) { + TALLOC_CTX *frame = talloc_stackframe(); ADS_STATUS status; ADS_MODLIST mods; fstring my_fqdn; @@ -506,7 +507,7 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, return status; } - status = libnet_join_get_machine_spns(mem_ctx, + status = libnet_join_get_machine_spns(frame, r, discard_const_p(char **, &spn_array), &num_spns); @@ -516,40 +517,46 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, /* Windows only creates HOST/shortname & HOST/fqdn. */ - spn = talloc_asprintf(mem_ctx, "HOST/%s", r->in.machine_name); + spn = talloc_asprintf(frame, "HOST/%s", r->in.machine_name); if (spn == NULL) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } if (!strupper_m(spn)) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } ok = ads_element_in_array(spn_array, num_spns, spn); if (!ok) { - ok = add_string_to_array(spn_array, spn, + ok = add_string_to_array(frame, spn, &spn_array, &num_spns); if (!ok) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } } fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name, lp_dnsdomain()); if (!strlower_m(my_fqdn)) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } - spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn); + spn = talloc_asprintf(frame, "HOST/%s", my_fqdn); if (spn == NULL) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } ok = ads_element_in_array(spn_array, num_spns, spn); if (!ok) { - ok = add_string_to_array(spn_array, spn, + ok = add_string_to_array(frame, spn, &spn_array, &num_spns); if (!ok) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } } @@ -559,28 +566,26 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, /* * Add HOST/NETBIOSNAME */ - spn = talloc_asprintf(mem_ctx, "HOST/%s", *netbios_aliases); + spn = talloc_asprintf(frame, "HOST/%s", *netbios_aliases); if (spn == NULL) { - TALLOC_FREE(spn); - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } if (!strupper_m(spn)) { - TALLOC_FREE(spn); - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } ok = ads_element_in_array(spn_array, num_spns, spn); if (ok) { - TALLOC_FREE(spn); continue; } ok = add_string_to_array(spn_array, spn, &spn_array, &num_spns); if (!ok) { - TALLOC_FREE(spn); - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } - TALLOC_FREE(spn); /* * Add HOST/netbiosname.domainname @@ -589,51 +594,56 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, *netbios_aliases, lp_dnsdomain()); - spn = talloc_asprintf(mem_ctx, "HOST/%s", my_fqdn); + spn = talloc_asprintf(frame, "HOST/%s", my_fqdn); if (spn == NULL) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } ok = ads_element_in_array(spn_array, num_spns, spn); if (ok) { - TALLOC_FREE(spn); continue; } ok = add_string_to_array(spn_array, spn, &spn_array, &num_spns); if (!ok) { - TALLOC_FREE(spn); - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } - TALLOC_FREE(spn); } /* make sure to NULL terminate the array */ - spn_array = talloc_realloc(mem_ctx, spn_array, const char *, num_spns + 1); + spn_array = talloc_realloc(frame, spn_array, const char *, num_spns + 1); if (spn_array == NULL) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } spn_array[num_spns] = NULL; mods = ads_init_mods(mem_ctx); if (!mods) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } /* fields of primary importance */ status = ads_mod_str(mem_ctx, &mods, "dNSHostName", my_fqdn); if (!ADS_ERR_OK(status)) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } status = ads_mod_strlist(mem_ctx, &mods, "servicePrincipalName", spn_array); if (!ADS_ERR_OK(status)) { - return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; } - return ads_gen_mod(r->in.ads, r->out.dn, mods); + status = ads_gen_mod(r->in.ads, r->out.dn, mods); + +done: + TALLOC_FREE(frame); + return status; } /**************************************************************** -- 2.17.1 From 526ad3a904ad9d18219cc5d06313cfa2318fc2ef Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Wed, 18 Sep 2019 23:15:57 +0300 Subject: [PATCH 299/376] libnet_join_set_machine_spn: simplify adding uniq spn to array and do not skip adding a fully qualified spn to netbios-aliases in case a short spn already existed. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14116 Signed-off-by: Isaac Boukris Reviewed-by: Ralph Boehme Reviewed-by: Alexander Bokovoy --- source3/libnet/libnet_join.c | 56 +++++++++++++++--------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index 15659b5ab43..71d45276392 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -483,6 +483,19 @@ static ADS_STATUS libnet_join_get_machine_spns(TALLOC_CTX *mem_ctx, return status; } +static ADS_STATUS add_uniq_spn(TALLOC_CTX *mem_ctx, const char *spn, + const char ***array, size_t *num) +{ + bool ok = ads_element_in_array(*array, *num, spn); + if (!ok) { + ok = add_string_to_array(mem_ctx, spn, array, num); + if (!ok) { + return ADS_ERROR_LDAP(LDAP_NO_MEMORY); + } + } + return ADS_SUCCESS; +} + /**************************************************************** Set a machines dNSHostName and servicePrincipalName attributes ****************************************************************/ @@ -497,7 +510,6 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, const char **spn_array = NULL; size_t num_spns = 0; char *spn = NULL; - bool ok; const char **netbios_aliases = NULL; /* Find our DN */ @@ -527,14 +539,9 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, goto done; } - ok = ads_element_in_array(spn_array, num_spns, spn); - if (!ok) { - ok = add_string_to_array(frame, spn, - &spn_array, &num_spns); - if (!ok) { - status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); - goto done; - } + status = add_uniq_spn(frame, spn, &spn_array, &num_spns); + if (!ADS_ERR_OK(status)) { + goto done; } fstr_sprintf(my_fqdn, "%s.%s", r->in.machine_name, lp_dnsdomain()); @@ -550,14 +557,9 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, goto done; } - ok = ads_element_in_array(spn_array, num_spns, spn); - if (!ok) { - ok = add_string_to_array(frame, spn, - &spn_array, &num_spns); - if (!ok) { - status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); - goto done; - } + status = add_uniq_spn(frame, spn, &spn_array, &num_spns); + if (!ADS_ERR_OK(status)) { + goto done; } for (netbios_aliases = lp_netbios_aliases(); @@ -576,14 +578,8 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, goto done; } - ok = ads_element_in_array(spn_array, num_spns, spn); - if (ok) { - continue; - } - ok = add_string_to_array(spn_array, spn, - &spn_array, &num_spns); - if (!ok) { - status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = add_uniq_spn(frame, spn, &spn_array, &num_spns); + if (!ADS_ERR_OK(status)) { goto done; } @@ -600,14 +596,8 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, goto done; } - ok = ads_element_in_array(spn_array, num_spns, spn); - if (ok) { - continue; - } - ok = add_string_to_array(spn_array, spn, - &spn_array, &num_spns); - if (!ok) { - status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + status = add_uniq_spn(frame, spn, &spn_array, &num_spns); + if (!ADS_ERR_OK(status)) { goto done; } } -- 2.17.1 From 35da7673e882dfc16e95bbfa1bea49ee837d33a5 Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Tue, 17 Sep 2019 21:38:07 +0300 Subject: [PATCH 300/376] docs-xml: add "additional dns hostnames" smb.conf option BUG: https://bugzilla.samba.org/show_bug.cgi?id=14116 Signed-off-by: Isaac Boukris Reviewed-by: Ralph Boehme Reviewed-by: Alexander Bokovoy --- docs-xml/smbdotconf/base/additionaldnshostnames.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 docs-xml/smbdotconf/base/additionaldnshostnames.xml diff --git a/docs-xml/smbdotconf/base/additionaldnshostnames.xml b/docs-xml/smbdotconf/base/additionaldnshostnames.xml new file mode 100644 index 00000000000..ddc04ee9f81 --- /dev/null +++ b/docs-xml/smbdotconf/base/additionaldnshostnames.xml @@ -0,0 +1,11 @@ + + + A list of additional DNS names by which this host can be identified + + +empty string (no additional dns names) + host2.example.com host3.other.com + -- 2.17.1 From b30b3073f9c0aa052b354385b2878f9a17756bee Mon Sep 17 00:00:00 2001 From: Isaac Boukris Date: Fri, 13 Sep 2019 10:56:10 +0300 Subject: [PATCH 301/376] libnet_join: add SPNs for additional-dns-hostnames entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and set msDS-AdditionalDnsHostName to the specified list. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14116 Signed-off-by: Isaac Boukris Reviewed-by: Ralph Boehme Reviewed-by: Alexander Bokovoy Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Fri Oct 25 10:43:08 UTC 2019 on sn-devel-184 Autobuild-User(v4-11-test): Karolin Seeger Autobuild-Date(v4-11-test): Tue Nov 5 13:57:30 UTC 2019 on sn-devel-184 --- source3/libnet/libnet_join.c | 27 +++++++++++++++++++++++++++ testprogs/blackbox/test_net_ads.sh | 10 +++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index 71d45276392..9d4f656ffec 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -511,6 +511,7 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, size_t num_spns = 0; char *spn = NULL; const char **netbios_aliases = NULL; + const char **addl_hostnames = NULL; /* Find our DN */ @@ -602,6 +603,22 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, } } + for (addl_hostnames = lp_additional_dns_hostnames(); + addl_hostnames != NULL && *addl_hostnames != NULL; + addl_hostnames++) { + + spn = talloc_asprintf(frame, "HOST/%s", *addl_hostnames); + if (spn == NULL) { + status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); + goto done; + } + + status = add_uniq_spn(frame, spn, &spn_array, &num_spns); + if (!ADS_ERR_OK(status)) { + goto done; + } + } + /* make sure to NULL terminate the array */ spn_array = talloc_realloc(frame, spn_array, const char *, num_spns + 1); if (spn_array == NULL) { @@ -629,6 +646,16 @@ static ADS_STATUS libnet_join_set_machine_spn(TALLOC_CTX *mem_ctx, goto done; } + addl_hostnames = lp_additional_dns_hostnames(); + if (addl_hostnames != NULL && *addl_hostnames != NULL) { + status = ads_mod_strlist(mem_ctx, &mods, + "msDS-AdditionalDnsHostName", + addl_hostnames); + if (!ADS_ERR_OK(status)) { + goto done; + } + } + status = ads_gen_mod(r->in.ads, r->out.dn, mods); done: diff --git a/testprogs/blackbox/test_net_ads.sh b/testprogs/blackbox/test_net_ads.sh index ef6f99ddea4..8bcff006b8e 100755 --- a/testprogs/blackbox/test_net_ads.sh +++ b/testprogs/blackbox/test_net_ads.sh @@ -202,13 +202,21 @@ base_dn="DC=addom,DC=samba,DC=example,DC=com" computers_dn="CN=Computers,$base_dn" testit "ldb check for existence of machine account" $ldbsearch -U$DC_USERNAME%$DC_PASSWORD -H ldap://$SERVER.$REALM -s base -b "cn=$HOSTNAME,$computers_dn" || failed=`expr $failed + 1` -testit "join" $VALGRIND $net_tool ads join -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` +dns_alias1="${netbios}_alias1.other.${lc_realm}" +dns_alias2="${netbios}_alias2.other2.${lc_realm}" +testit "join" $VALGRIND $net_tool --option=additionaldnshostnames=$dns_alias1,$dns_alias2 ads join -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` testit "testjoin" $VALGRIND $net_tool ads testjoin || failed=`expr $failed + 1` testit_grep "check dNSHostName" $fqdn $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ dNSHostName || failed=`expr $failed + 1` testit_grep "check SPN" ${uc_netbios}.${lc_realm} $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1` +testit_grep "dns alias SPN" $dns_alias1 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1` +testit_grep "dns alias SPN" $dns_alias2 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ servicePrincipalName || failed=`expr $failed + 1` + +testit_grep "dns alias addl" $dns_alias1 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1` +testit_grep "dns alias addl" $dns_alias2 $VALGRIND $net_tool ads search -P samaccountname=$netbios\$ msDS-AdditionalDnsHostName || failed=`expr $failed + 1` + ##Goodbye... testit "leave" $VALGRIND $net_tool ads leave -U$DC_USERNAME%$DC_PASSWORD || failed=`expr $failed + 1` -- 2.17.1 From ac3cb59fd4f3736547979a780508c51106b84d8e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sat, 4 May 2019 12:12:04 +0200 Subject: [PATCH 302/376] s3:dbwrap: initialize messaging before getting the ctdb connection This is a better fix for bug #13465. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13925 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit ca95d7f41b683b4d7ac59ed6ee709d44abfe2019) --- source3/lib/dbwrap/dbwrap_open.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/lib/dbwrap/dbwrap_open.c b/source3/lib/dbwrap/dbwrap_open.c index c8dfd9103a8..20084bca471 100644 --- a/source3/lib/dbwrap/dbwrap_open.c +++ b/source3/lib/dbwrap/dbwrap_open.c @@ -141,13 +141,19 @@ struct db_context *db_open(TALLOC_CTX *mem_ctx, struct messaging_context *msg_ctx; struct ctdbd_connection *conn; + /* + * Initialize messaging before getting the ctdb + * connection, as the ctdb connection requires messaging + * to be initialized. + */ + msg_ctx = global_messaging_context(); + conn = messaging_ctdb_connection(); if (conn == NULL) { DBG_WARNING("No ctdb connection\n"); errno = EIO; return NULL; } - msg_ctx = global_messaging_context(); result = db_open_ctdb(mem_ctx, msg_ctx, base, hash_size, -- 2.17.1 From 098ddd6fe4e7d95cba6fa50749479f5243f671e9 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sat, 4 May 2019 12:12:48 +0200 Subject: [PATCH 303/376] s3: remove now unneeded call to cmdline_messaging_context() This was only needed as dbwrap_open() had a bug where it asked for the ctdb connection before initializing messaging. The previous commit fixed that so we can now safely remove the calls to cmdline_messaging_context() from all tools that don't use messaging. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13925 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Thu Oct 24 09:33:47 UTC 2019 on sn-devel-184 (cherry picked from commit 9471508391fd3bcf199b1e94f8d9ee2b956e8f8e) --- source3/lib/popt_common_cmdline.c | 7 ------- source3/utils/dbwrap_tool.c | 2 -- source3/utils/eventlogadm.c | 3 --- source3/utils/ntlm_auth.c | 2 -- source3/utils/pdbedit.c | 2 -- source3/utils/sharesec.c | 1 - source3/utils/smbget.c | 2 -- source3/utils/smbpasswd.c | 2 -- source3/utils/testparm.c | 2 -- 9 files changed, 23 deletions(-) diff --git a/source3/lib/popt_common_cmdline.c b/source3/lib/popt_common_cmdline.c index 79e34847f48..39a787510a3 100644 --- a/source3/lib/popt_common_cmdline.c +++ b/source3/lib/popt_common_cmdline.c @@ -102,15 +102,8 @@ static void popt_common_credentials_callback(poptContext con, } if (reason == POPT_CALLBACK_REASON_POST) { - struct messaging_context *msg_ctx = NULL; bool ok; - msg_ctx = cmdline_messaging_context(get_dyn_CONFIGFILE()); - if (msg_ctx == NULL) { - fprintf(stderr, "Unable to initialize " - "messaging context\n"); - } - ok = lp_load_client(get_dyn_CONFIGFILE()); if (!ok) { const char *pname = poptGetInvocationName(con); diff --git a/source3/utils/dbwrap_tool.c b/source3/utils/dbwrap_tool.c index 2808a5d68bf..153a4459ee0 100644 --- a/source3/utils/dbwrap_tool.c +++ b/source3/utils/dbwrap_tool.c @@ -422,8 +422,6 @@ int main(int argc, const char **argv) while (extra_argv[extra_argc]) extra_argc++; } - cmdline_messaging_context(get_dyn_CONFIGFILE()); - lp_load_global(get_dyn_CONFIGFILE()); if ((extra_argc < 2) || (extra_argc > 5)) { diff --git a/source3/utils/eventlogadm.c b/source3/utils/eventlogadm.c index db874dfae8a..2770fffa48c 100644 --- a/source3/utils/eventlogadm.c +++ b/source3/utils/eventlogadm.c @@ -473,9 +473,6 @@ int main( int argc, char *argv[] ) exit( 1 ); } - cmdline_messaging_context(configfile == NULL ? - get_dyn_CONFIGFILE() : configfile); - if ( configfile == NULL ) { lp_load_global(get_dyn_CONFIGFILE()); } else if (!lp_load_global(configfile)) { diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 2be641c891c..87f6554ae4f 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -2504,8 +2504,6 @@ enum { poptFreeContext(pc); - cmdline_messaging_context(get_dyn_CONFIGFILE()); - if (!lp_load_global(get_dyn_CONFIGFILE())) { d_fprintf(stderr, "ntlm_auth: error opening config file %s. Error was %s\n", get_dyn_CONFIGFILE(), strerror(errno)); diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c index 74f8c3b0b2f..14edbaeceea 100644 --- a/source3/utils/pdbedit.c +++ b/source3/utils/pdbedit.c @@ -1128,8 +1128,6 @@ int main(int argc, const char **argv) if (user_name == NULL) user_name = poptGetArg(pc); - cmdline_messaging_context(get_dyn_CONFIGFILE()); - if (!lp_load_global(get_dyn_CONFIGFILE())) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", get_dyn_CONFIGFILE()); exit(1); diff --git a/source3/utils/sharesec.c b/source3/utils/sharesec.c index 2ea81b9adfa..10c347eaac3 100644 --- a/source3/utils/sharesec.c +++ b/source3/utils/sharesec.c @@ -501,7 +501,6 @@ int main(int argc, const char *argv[]) setlinebuf(stdout); - cmdline_messaging_context(get_dyn_CONFIGFILE()); lp_load_with_registry_shares(get_dyn_CONFIGFILE()); /* check for initializing secrets.tdb first */ diff --git a/source3/utils/smbget.c b/source3/utils/smbget.c index 58690be56e3..a948a336445 100644 --- a/source3/utils/smbget.c +++ b/source3/utils/smbget.c @@ -1003,8 +1003,6 @@ int main(int argc, char **argv) popt_burn_cmdline_password(argc, argv); - cmdline_messaging_context(get_dyn_CONFIGFILE()); - if (smbc_init(get_auth_data, opt.debuglevel) < 0) { fprintf(stderr, "Unable to initialize libsmbclient\n"); return 1; diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c index 8e2b9d7f80f..a6509abe5cb 100644 --- a/source3/utils/smbpasswd.c +++ b/source3/utils/smbpasswd.c @@ -197,8 +197,6 @@ static int process_options(int argc, char **argv, int local_flags) usage(); } - cmdline_messaging_context(configfile); - if (!lp_load_global(configfile)) { fprintf(stderr, "Can't load %s - run testparm to debug it\n", configfile); diff --git a/source3/utils/testparm.c b/source3/utils/testparm.c index efa58a6a417..9ba625da4bf 100644 --- a/source3/utils/testparm.c +++ b/source3/utils/testparm.c @@ -742,8 +742,6 @@ static void do_per_share_checks(int s) goto done; } - cmdline_messaging_context(config_file); - fprintf(stderr,"Load smb config files from %s\n",config_file); if (!lp_load_with_registry_shares(config_file)) { -- 2.17.1 From eacdde195ac595bce9b35febb13b9723851fbb41 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 5 Aug 2019 10:59:22 +0200 Subject: [PATCH 304/376] s3:smbd: Incomplete conversion of former parametric options BUG: https://bugzilla.samba.org/show_bug.cgi?id=14069 RN: Incomplete conversion of former parametric options Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke (backported from commit ea17bd5539eb0be7a446b99c8b6baa4aa1ab273f) --- source3/modules/vfs_ceph.c | 2 +- source3/modules/vfs_glusterfs.c | 2 +- source3/modules/vfs_gpfs.c | 2 +- source3/smbd/reply.c | 4 ++-- source3/smbd/trans2.c | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c index 1b293ddb1b0..28363f003c2 100644 --- a/source3/modules/vfs_ceph.c +++ b/source3/modules/vfs_ceph.c @@ -146,7 +146,7 @@ static int cephwrap_connect(struct vfs_handle_struct *handle, const char *servi /* * Unless we have an async implementation of getxattrat turn this off. */ - lp_do_parameter(SNUM(handle->conn), "smbd:async dosmode", "false"); + lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false"); return 0; diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index afb34b4b47c..8827bf018ab 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -367,7 +367,7 @@ static int vfs_gluster_connect(struct vfs_handle_struct *handle, /* * Unless we have an async implementation of getxattrat turn this off. */ - lp_do_parameter(SNUM(handle->conn), "smbd:async dosmode", "false"); + lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false"); done: if (ret < 0) { diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index f0d5074d36b..22848496178 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -2195,7 +2195,7 @@ static int vfs_gpfs_connect(struct vfs_handle_struct *handle, * Unless we have an async implementation of get_dos_attributes turn * this off. */ - lp_do_parameter(SNUM(handle->conn), "smbd:async dosmode", "false"); + lp_do_parameter(SNUM(handle->conn), "smbd async dosmode", "false"); return 0; } diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 35d1ae772d5..65ac729c732 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -1386,7 +1386,7 @@ void reply_getatr(struct smb_request *req) const char *p; NTSTATUS status; TALLOC_CTX *ctx = talloc_tos(); - bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); + bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn)); START_PROFILE(SMBgetatr); @@ -1769,7 +1769,7 @@ void reply_search(struct smb_request *req) bool mask_contains_wcard = False; bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False; TALLOC_CTX *ctx = talloc_tos(); - bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); + bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn)); struct dptr_struct *dirptr = NULL; struct smbXsrv_connection *xconn = req->xconn; struct smbd_server_connection *sconn = req->sconn; diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 0539b35bb73..b0616f15ade 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -2710,7 +2710,7 @@ static void call_trans2findfirst(connection_struct *conn, bool mask_contains_wcard = False; struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; - bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); + bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn)); struct dptr_struct *dirptr = NULL; struct smbd_server_connection *sconn = req->sconn; uint32_t ucf_flags = UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP | @@ -3126,7 +3126,7 @@ static void call_trans2findnext(connection_struct *conn, int space_remaining; struct ea_list *ea_list = NULL; NTSTATUS ntstatus = NT_STATUS_OK; - bool ask_sharemode = lp_parm_bool(SNUM(conn), "smbd", "search ask sharemode", true); + bool ask_sharemode = lp_smbd_search_ask_sharemode(SNUM(conn)); TALL