The branch, v4-13-stable has been updated via 85bb95881bb VERSION: Disable GIT_SNAPSHOT for the 4.13.10 release. via 22882df5ac4 WHATSNEW: Add release notes for Samba 4.13.10. via b9b1d98af4c smbXsrv_{open,session,tcon}: protect smbXsrv_{open,session,tcon}_global_traverse_fn against invalid records via 7065f203a9f gensec_krb5: restore ipv6 support for kpasswd via 82e0f3e7997 netcmd: Use next_free_rid() function to calculate a SID for restoring a backup via e5c3a675464 python/tests/dsdb: Add tests for RID allocation functions via afad2fd9e24 dsdb: Add next_free_rid() function to allocate a RID without modifying the database via b3d59842fd9 netcmd: Add tests for performing an offline backup immediately after joining a domain via 00444ac64f5 netcmd: Ignore rIDUsedPool attribute in offline domain backup test via 445fb770c77 netcmd: Fix error-checking condition via 303a0ecdd9d netcmd: Avoid database corruption by opting not to create database files during an offline domain backup via 54c353e9ad6 netcmd: Determine which files are to be copied for an offline domain backup via 4a68b1cb2dc netcmd: Add test for an offline backup of nested directories via 6569d0b9967 netcmd: Add test for an offline backup of a directory containing hardlinks via d0bde5703b2 samba-tool: Give better error information when the 'domain backup restore' fails with a duplicate SID via 6e284db7877 samba-tool domain backup: Confirm the sidForRestore we will put into the backup is free via b01c4526fef s3: smbd: Fix uninitialized memory read in process_symlink_open() when used with vfs_shadow_copy2(). via a708c9b48a2 mdssvc: avoid direct filesystem access, use the VFS via 9f4e3da5eec mdssvc: chdir() to the conn of the RPC request via 7c924449b87 mdssvc: maintain a connection struct in the mds_ctx via 48b2dc3c5cc smbd: add create_conn_struct_cwd() via 60e091a153e smbd: pass tevent context to create_conn_struct_as_root() via 63ff1e37d55 mdssvc: pass messaging context to mds_init_ctx() via dce4c5ed911 mdssvc: don't fail mds_add_result() if result is not found in CNID set via 0484804d9f6 mdssvc: use a helper variable in mds_add_result() via b0746202c20 s3: smbd: Remove erroneous TALLOC_FREE(smb_fname_parent) in change_file_owner_to_parent() error path. via 0b75c272368 s3: lib: Fix talloc heirarcy error in parent_smb_fname(). via 5d4bbaff8b6 smbd: correctly initialize close timestamp fields via 37233cbdf8f torture: add a test that verifies SMB2 close fields without postqueryattrib via c67dbd55aad ctdb: Fix a crash in run_proc_signal_handler() via 037f4b8fb9a ctdb: Introduce output before and after the 10-second timeout via 87265cef4b7 ctdb: Wait for SIGCHLD if script timed out via e70a8cbdb4a ctdb: Introduce a helper variable in run_event_test.c via 5e55d2c0dcf ctdb: Call run_event_recv() in a callback function via 83511576a1c ctdb: fix typos via abcddbae481 s3: smbd: Ensure POSIX default ACL is mapped into returned Windows ACL for directory handles. from 46c071544f1 VERSION: Bump version up to 4.13.10...
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-13-stable - Log ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: VERSION | 2 +- WHATSNEW.txt | 70 ++++++- ctdb/common/run_proc.c | 6 +- ctdb/tests/UNIT/cunit/run_event_001.sh | 3 + ctdb/tests/src/run_event_test.c | 52 ++++- python/samba/netcmd/domain_backup.py | 173 +++++++++++----- python/samba/samdb.py | 105 ++++++++++ python/samba/tests/domain_backup_offline.py | 162 ++++++++++++--- python/samba/tests/dsdb.py | 305 +++++++++++++++++++++++++++- source3/lib/filename_util.c | 2 +- source3/rpc_server/mdssvc/mdssvc.c | 127 ++++++++++-- source3/rpc_server/mdssvc/mdssvc.h | 2 + source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 1 + source3/smbd/msdfs.c | 54 ++++- source3/smbd/open.c | 18 +- source3/smbd/posix_acls.c | 12 +- source3/smbd/proto.h | 8 + source3/smbd/smb2_close.c | 8 +- source3/smbd/smbXsrv_open.c | 9 + source3/smbd/smbXsrv_session.c | 7 + source3/smbd/smbXsrv_tcon.c | 7 + source4/auth/gensec/gensec_krb5.c | 6 +- source4/selftest/tests.py | 2 +- source4/torture/smb2/timestamps.c | 65 ++++++ 24 files changed, 1073 insertions(+), 133 deletions(-) Changeset truncated at 500 lines: diff --git a/VERSION b/VERSION index addb12d75e0..d05f3595233 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 # diff --git a/WHATSNEW.txt b/WHATSNEW.txt index da680c071d9..c141d32b62e 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,3 +1,70 @@ + =============================== + Release Notes for Samba 4.13.10 + July 14, 2021 + =============================== + + +This is the latest stable release of the Samba 4.13 release series. + + +Changes since 4.13.9 +-------------------- + +o Jeremy Allison <j...@samba.org> + * BUG 14708: s3: smbd: Ensure POSIX default ACL is mapped into returned + Windows ACL for directory handles. + * BUG 14721: Take a copy to make sure we don't reference free'd memory. + * BUG 14722: s3: lib: Fix talloc heirarcy error in parent_smb_fname(). + * BUG 14736: s3: smbd: Remove erroneous TALLOC_FREE(smb_fname_parent) in + change_file_owner_to_parent() error path. + +o Andrew Bartlett <abart...@samba.org> + * BUG 14575: samba-tool: Give better error information when the + 'domain backup restore' fails with a duplicate SID. + +o Ralph Boehme <s...@samba.org> + * BUG 14714: smbd: Correctly initialize close timestamp fields. + * BUG 14740: Spotlight RPC service doesn't work with vfs_glusterfs. + +o Volker Lendecke <v...@samba.org> + * BUG 14475: ctdb: Fix a crash in run_proc_signal_handler(). + +o Stefan Metzmacher <me...@samba.org> + * BUG 14750: gensec_krb5: Restore ipv6 support for kpasswd. + * BUG 14752: smbXsrv_{open,session,tcon}: Protect + smbXsrv_{open,session,tcon}_global_traverse_fn against invalid records. + +o Joseph Sutton <josephsut...@catalyst.net.nz> + * BUG 14027: samba-tool domain backup offline doesn't work against bind DLZ + backend. + * BUG 14669: netcmd: Use next_free_rid() function to calculate a SID for + restoring a backup. + + +####################################### +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.13.9 May 11, 2021 @@ -61,8 +128,7 @@ database (https://bugzilla.samba.org/). ====================================================================== -Release notes for older releases follow: ----------------------------------------- +---------------------------------------------------------------------- ============================== diff --git a/ctdb/common/run_proc.c b/ctdb/common/run_proc.c index 0c3c1de72fe..d55af6c3a1e 100644 --- a/ctdb/common/run_proc.c +++ b/ctdb/common/run_proc.c @@ -426,7 +426,7 @@ static void run_proc_done(struct tevent_req *req) state->result = state->proc->result; if (state->proc->output != NULL) { - state->output = talloc_steal(state, state->proc->output); + state->output = talloc_move(state, &state->proc->output); } talloc_steal(state, state->proc); @@ -464,7 +464,7 @@ static void run_proc_timedout(struct tevent_req *subreq) state->result.err = ETIMEDOUT; if (state->proc->output != NULL) { - state->output = talloc_steal(state, state->proc->output); + state->output = talloc_move(state, &state->proc->output); } state->pid = state->proc->pid; @@ -495,7 +495,7 @@ bool run_proc_recv(struct tevent_req *req, int *perr, } if (output != NULL) { - *output = talloc_steal(mem_ctx, state->output); + *output = talloc_move(mem_ctx, &state->output); } return true; diff --git a/ctdb/tests/UNIT/cunit/run_event_001.sh b/ctdb/tests/UNIT/cunit/run_event_001.sh index 50051bfaab2..4df3b4bdad6 100755 --- a/ctdb/tests/UNIT/cunit/run_event_001.sh +++ b/ctdb/tests/UNIT/cunit/run_event_001.sh @@ -113,7 +113,9 @@ unit_test run_event_test "$scriptdir" run 10 monitor cat > "$scriptdir/22.bar.script" <<EOF #!/bin/sh +echo before sleep sleep 10 +echo after sleep EOF # Timed out script @@ -124,6 +126,7 @@ unit_test run_event_test "$scriptdir" enable 22.bar ok <<EOF 11.foo: hello +22.bar: before sleep Event monitor completed with result=-$(errcode ETIMEDOUT) 11.foo result=0 22.bar result=-$(errcode ETIMEDOUT) diff --git a/ctdb/tests/src/run_event_test.c b/ctdb/tests/src/run_event_test.c index cfe5f161d1d..94548647014 100644 --- a/ctdb/tests/src/run_event_test.c +++ b/ctdb/tests/src/run_event_test.c @@ -52,6 +52,19 @@ static char *compact_args(const char **argv, int argc, int from) return arg_str; } +static void run_done(struct tevent_req *req) +{ + struct run_event_script_list **script_list = + tevent_req_callback_data_void(req); + bool status; + int ret; + + status = run_event_recv(req, &ret, NULL, script_list); + if (!status) { + fprintf(stderr, "run_event_recv() failed, ret=%d\n", ret); + } +} + static void do_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct run_event_context *run_ctx, int argc, const char **argv) @@ -61,8 +74,8 @@ static void do_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct run_event_script_list *script_list = NULL; char *arg_str; unsigned int i; - int ret, t; - bool status; + int t; + bool wait_for_signal = false; if (argc < 5) { usage(argv[0]); @@ -86,17 +99,13 @@ static void do_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev, timeout, false); if (req == NULL) { - fprintf(stderr, "run_proc_send() failed\n"); + fprintf(stderr, "run_event_send() failed\n"); return; } - tevent_req_poll(req, ev); + tevent_req_set_callback(req, run_done, &script_list); - status = run_event_recv(req, &ret, mem_ctx, &script_list); - if (! status) { - fprintf(stderr, "run_proc_recv() failed, ret=%d\n", ret); - return; - } + tevent_req_poll(req, ev); if (script_list == NULL || script_list->num_scripts == 0) { printf("No event scripts found\n"); @@ -106,9 +115,30 @@ static void do_run(TALLOC_CTX *mem_ctx, struct tevent_context *ev, printf("Event %s completed with result=%d\n", argv[4], script_list->summary); for (i=0; i<script_list->num_scripts; i++) { - printf("%s result=%d\n", script_list->script[i].name, - script_list->script[i].summary); + struct run_event_script *s = &script_list->script[i]; + printf("%s result=%d\n", s->name, s->summary); + + if (s->summary == -ETIMEDOUT) { + wait_for_signal = true; + } + } + + TALLOC_FREE(script_list); + TALLOC_FREE(req); + + if (!wait_for_signal) { + return; } + + req = tevent_wakeup_send( + ev, ev, tevent_timeval_current_ofs(10, 0)); + if (req == NULL) { + fprintf(stderr, "Could not wait for signal\n"); + return; + } + + tevent_req_poll(req, ev); + TALLOC_FREE(req); } static void do_list(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/python/samba/netcmd/domain_backup.py b/python/samba/netcmd/domain_backup.py index a3dc7fb454f..a629b31d70f 100644 --- a/python/samba/netcmd/domain_backup.py +++ b/python/samba/netcmd/domain_backup.py @@ -27,6 +27,7 @@ import tdb import samba.getopt as options from samba.samdb import SamDB, get_default_backend_store import ldb +from ldb import LdbError from samba.samba3 import libsmb_samba_internal as libsmb from samba.samba3 import param as s3param from samba.ntacls import backup_online, backup_restore, backup_offline @@ -60,53 +61,50 @@ from samba.ndr import ndr_pack # This ensures that the restored DC's SID won't clash with any other RIDs # already in use in the domain def get_sid_for_restore(samdb, logger): - # Find the DN of the RID set of the server - res = samdb.search(base=ldb.Dn(samdb, samdb.get_serverName()), - scope=ldb.SCOPE_BASE, attrs=["serverReference"]) - server_ref_dn = ldb.Dn(samdb, str(res[0]['serverReference'][0])) - res = samdb.search(base=server_ref_dn, - scope=ldb.SCOPE_BASE, - attrs=['rIDSetReferences']) - rid_set_dn = ldb.Dn(samdb, str(res[0]['rIDSetReferences'][0])) - - # Get the alloc pools and next RID of the RID set - res = samdb.search(base=rid_set_dn, - scope=ldb.SCOPE_SUBTREE, - expression="(rIDNextRID=*)", - attrs=['rIDAllocationPool', - 'rIDPreviousAllocationPool', - 'rIDNextRID']) - - # Decode the bounds of the RID allocation pools + # Allocate a new RID without modifying the database. This should be safe, + # because we acquire the RID master role after creating an account using + # this RID during the restore process. Acquiring the RID master role + # creates a new RID pool which we will fetch RIDs from, so we shouldn't get + # duplicates. try: - rid = int(res[0].get('rIDNextRID')[0]) - except IndexError: - logger.info("The RID pool for this DC is not initalized " - "(e.g. it may be a fairly new DC).") - logger.info("To initialize it, create a temporary user on this DC " - "(you can delete it later).") - raise CommandError("Cannot create backup - " - "please initialize this DC's RID pool first.") - - def split_val(num): - high = (0xFFFFFFFF00000000 & int(num)) >> 32 - low = 0x00000000FFFFFFFF & int(num) - return low, high - pool_l, pool_h = split_val(res[0].get('rIDPreviousAllocationPool')[0]) - npool_l, npool_h = split_val(res[0].get('rIDAllocationPool')[0]) - - # Calculate next RID based on pool bounds - if rid == npool_h: - raise CommandError('Out of RIDs, finished AllocPool') - if rid == pool_h: - if pool_h == npool_h: - raise CommandError('Out of RIDs, finished PrevAllocPool.') - rid = npool_l - else: - rid += 1 + rid = samdb.next_free_rid() + except LdbError as err: + logger.info("A SID could not be allocated for restoring the domain. " + "Either no RID Set was found on this DC, " + "or the RID Set was not usable.") + logger.info("To initialise this DC's RID pools, obtain a RID Set from " + "this domain's RID master, or run samba-tool dbcheck " + "to fix the existing RID Set.") + raise CommandError("Cannot create backup", err) # Construct full SID sid = dom_sid(samdb.get_domain_sid()) + sid_for_restore = str(sid) + '-' + str(rid) + + # Confirm the SID is not already in use + try: + res = samdb.search(scope=ldb.SCOPE_BASE, + base='<SID=%s>' % sid_for_restore, + attrs=[], + controls=['show_deleted:1', + 'show_recycled:1']) + if len(res) != 1: + # This case makes no sense, but neither does a corrupt RID set + raise CommandError("Cannot create backup - " + "this DC's RID pool is corrupt, " + "the next SID (%s) appears to be in use." % + sid_for_restore) + raise CommandError("Cannot create backup - " + "this DC's RID pool is corrupt, " + "the next SID %s points to existing object %s. " + "Please run samba-tool dbcheck on the source DC." % + (sid_for_restore, res[0].dn)) + except ldb.LdbError as e: + (enum, emsg) = e.args + if enum != ldb.ERR_NO_SUCH_OBJECT: + # We want NO_SUCH_OBJECT, anything else is a serious issue + raise + return str(sid) + '-' + str(rid) @@ -278,7 +276,8 @@ class cmd_domain_backup_online(samba.netcmd.Command): shutil.rmtree(paths.sysvol) # Edit the downloaded sam.ldb to mark it as a backup - samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp) + samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp, + flags=ldb.FLG_DONT_CREATE_DB) time_str = get_timestamp() add_backup_marker(samdb, "backupDate", time_str) add_backup_marker(samdb, "sidForRestore", new_sid) @@ -502,7 +501,8 @@ class cmd_domain_backup_restore(cmd_fsmo_seize): # open a DB connection to the restored DB private_dir = os.path.join(targetdir, 'private') samdb_path = os.path.join(private_dir, 'sam.ldb') - samdb = SamDB(url=samdb_path, session_info=system_session(), lp=lp) + samdb = SamDB(url=samdb_path, session_info=system_session(), lp=lp, + flags=ldb.FLG_DONT_CREATE_DB) backup_type = self.get_backup_type(samdb) if site is None: @@ -550,7 +550,50 @@ class cmd_domain_backup_restore(cmd_fsmo_seize): attrs=['sidForRestore']) sid = res[0].get('sidForRestore')[0] logger.info('Creating account with SID: ' + str(sid)) - ctx.join_add_objects(specified_sid=dom_sid(str(sid))) + try: + ctx.join_add_objects(specified_sid=dom_sid(str(sid))) + except LdbError as e: + (enum, emsg) = e.args + if enum != ldb.ERR_CONSTRAINT_VIOLATION: + raise + + dup_res = [] + try: + dup_res = samdb.search(base=ldb.Dn(samdb, "<SID=%s>" % sid), + scope=ldb.SCOPE_BASE, + attrs=['objectGUID'], + controls=["show_deleted:0", + "show_recycled:0"]) + except LdbError as dup_e: + (dup_enum, _) = dup_e.args + if dup_enum != ldb.ERR_NO_SUCH_OBJECT: + raise + + if (len(dup_res) != 1): + raise + + objectguid = samdb.schema_format_value("objectGUID", + dup_res[0]["objectGUID"][0]) + objectguid = objectguid.decode('utf-8') + logger.error("The RID Pool on the source DC for the backup in %s " + "may be corrupt " + "or in conflict with SIDs already allocated " + "in the domain. " % backup_file) + logger.error("Running 'samba-tool dbcheck' on the source " + "DC (and obtaining a new backup) may correct the issue.") + logger.error("Alternatively please obtain a new backup " + "against a different DC.") + logger.error("The SID we wish to use (%s) is recorded in " + "@SAMBA_DSDB as the sidForRestore attribute." + % sid) + + raise CommandError("Domain restore failed because there " + "is already an existing object (%s) " + "with SID %s and objectGUID %s. " + "This conflicts with " + "the new DC account we want to add " + "for the restored domain. " % ( + dup_res[0].dn, sid, objectguid)) m = ldb.Message() m.dn = ldb.Dn(samdb, '@ROOTDSE') @@ -568,7 +611,8 @@ class cmd_domain_backup_restore(cmd_fsmo_seize): host_ip, host_ip6, site) secrets_path = os.path.join(private_dir, 'secrets.ldb') - secrets_ldb = Ldb(secrets_path, session_info=system_session(), lp=lp) + secrets_ldb = Ldb(secrets_path, session_info=system_session(), lp=lp, + flags=ldb.FLG_DONT_CREATE_DB) secretsdb_self_join(secrets_ldb, domain=ctx.domain_name, realm=ctx.realm, dnsdomain=ctx.dnsdomain, netbiosname=ctx.myname, domainsid=ctx.domsid, @@ -860,7 +904,8 @@ class cmd_domain_backup_rename(samba.netcmd.Command): # connect to the local DB (making sure we use the new/renamed config) lp.load(paths.smbconf) - samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp) + samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp, + flags=ldb.FLG_DONT_CREATE_DB) # Edit the cloned sam.ldb to mark it as a backup time_str = get_timestamp() @@ -948,7 +993,8 @@ class cmd_domain_backup_offline(samba.netcmd.Command): # on the secrets.ldb file before backing up that file and secrets.tdb def backup_secrets(self, private_dir, lp, logger): secrets_path = os.path.join(private_dir, 'secrets') - secrets_obj = Ldb(secrets_path + '.ldb', lp=lp) + secrets_obj = Ldb(secrets_path + '.ldb', lp=lp, + flags=ldb.FLG_DONT_CREATE_DB) logger.info('Starting transaction on ' + secrets_path) secrets_obj.transaction_start() self.offline_tdb_copy(secrets_path + '.ldb') @@ -973,7 +1019,7 @@ class cmd_domain_backup_offline(samba.netcmd.Command): else: logger.info('Starting transaction on ' + sam_ldb_path) copy_function = self.offline_tdb_copy - sam_obj = Ldb(sam_ldb_path, lp=lp) + sam_obj = Ldb(sam_ldb_path, lp=lp, flags=ldb.FLG_DONT_CREATE_DB) sam_obj.transaction_start() logger.info(' backing up ' + sam_ldb_path) @@ -1025,9 +1071,14 @@ class cmd_domain_backup_offline(samba.netcmd.Command): check_targetdir(logger, targetdir) - samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp) + samdb = SamDB(url=paths.samdb, session_info=system_session(), lp=lp, + flags=ldb.FLG_RDONLY) sid = get_sid_for_restore(samdb, logger) + # Iterating over the directories in this specific order ensures that + # when the private directory contains hardlinks that are also contained + # in other directories to be backed up (such as in paths.binddns_dir), + # the hardlinks in the private directory take precedence. backup_dirs = [paths.private_dir, paths.state_dir, os.path.dirname(paths.smbconf)] # etc dir logger.info('running backup on dirs: {0}'.format(' '.join(backup_dirs))) @@ -1040,22 +1091,31 @@ class cmd_domain_backup_offline(samba.netcmd.Command): continue if working_dir.endswith('.sock') or '.sock/' in working_dir: continue + # The BIND DNS database can be regenerated, so it doesn't need + # to be backed up. + if working_dir.startswith(os.path.join(paths.binddns_dir, 'dns')): + continue for filename in filenames: - if filename in all_files: + full_path = os.path.join(working_dir, filename) + + # Ignore files that have already been added. This prevents + # duplicates if one backup dir is a subdirectory of another, + # or if backup dirs contain hardlinks. + if any(os.path.samefile(full_path, file) for file in all_files): continue # Assume existing backup files are from a previous backup. # Delete and ignore. if filename.endswith(self.backup_ext): - os.remove(os.path.join(working_dir, filename)) + os.remove(full_path) continue # Sock files are autogenerated at runtime, ignore. -- Samba Shared Repository