[SCM] Samba Shared Repository - branch v4-13-stable updated

Karolin Seeger kseeger at samba.org
Wed Jul 14 08:15:04 UTC 2021


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 <jra at 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 <abartlet at samba.org>
+   * BUG 14575: samba-tool: Give better error information when the
+     'domain backup restore' fails with a duplicate SID.
+
+o  Ralph Boehme <slow at samba.org>
+   * BUG 14714: smbd: Correctly initialize close timestamp fields.
+   * BUG 14740: Spotlight RPC service doesn't work with vfs_glusterfs.
+
+o  Volker Lendecke <vl at samba.org>
+   * BUG 14475: ctdb: Fix a crash in run_proc_signal_handler().
+
+o  Stefan Metzmacher <metze at 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 <josephsutton at 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



More information about the samba-cvs mailing list