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

Karolin Seeger kseeger at samba.org
Tue Jul 13 10:33:46 UTC 2021


The branch, v4-14-stable has been updated
       via  507cdfb744e VERSION: Disable GIT_SNAPSHOT for the 4.14.6 release.
       via  dc3702b5113 WHATSNEW: Add release notes for Samba 4.14.6.
       via  8f7ab597969 smbXsrv_{open,session,tcon}: protect smbXsrv_{open,session,tcon}_global_traverse_fn against invalid records
       via  c1662a81220 gensec_krb5: restore ipv6 support for kpasswd
       via  a6447a1dce1 netcmd: Use next_free_rid() function to calculate a SID for restoring a backup
       via  69d8b64fdc1 python/tests/dsdb: Add tests for RID allocation functions
       via  94ca97bd121 dsdb: Add next_free_rid() function to allocate a RID without modifying the database
       via  f9d2652a0b4 netcmd: Add tests for performing an offline backup immediately after joining a domain
       via  b226e83a3dc netcmd: Ignore rIDUsedPool attribute in offline domain backup test
       via  79029224ee0 netcmd: Fix error-checking condition
       via  c1ac591c197 netcmd: Avoid database corruption by opting not to create database files during an offline domain backup
       via  7a7bfba1d98 netcmd: Determine which files are to be copied for an offline domain backup
       via  5b361227e7c netcmd: Add test for an offline backup of nested directories
       via  b095932a303 netcmd: Add test for an offline backup of a directory containing hardlinks
       via  60714069b2c mdssvc: avoid direct filesystem access, use the VFS
       via  19115477256 mdssvc: chdir() to the conn of the RPC request
       via  f8e857aeed3 mdssvc: maintain a connection struct in the mds_ctx
       via  9439cfe7142 smbd: add create_conn_struct_cwd()
       via  5ee1c6a0b01 smbd: pass tevent context to create_conn_struct_as_root()
       via  b1cb178ab9d mdssvc: pass messaging context to mds_init_ctx()
       via  db5326a7f7a mdssvc: don't fail mds_add_result() if result is not found in CNID set
       via  6ce42a067f3 mdssvc: use a helper variable in mds_add_result()
       via  858a116e796 smbd: add synthetic_pathref()
       via  4936ad99859 s3: smbd: Remove erroneous TALLOC_FREE(smb_fname_parent) in change_file_owner_to_parent() error path.
       via  f8c4bcb0b22 s3/modules: fchmod: fallback to path based chmod if pathref
       via  866efccfa90 s3: VFS: default: Add proc_fd's fallback for vfswrap_fchown().
       via  35d7a23d720 s3: lib: Fix talloc heirarcy error in parent_smb_fname().
       via  42fa9f800fd smbd: fix pathref unlinking in create_file_unixpath()
       via  1c8ba016208 smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from call_trans2findfirst()
       via  c8355298be5 smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from copy_file()
       via  94fc3ac176a smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from copy_file()
       via  acd2c1fed8d smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from rename_internals()
       via  fc8becea75d smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from rename_internals()
       via  89851bdfb8a smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from reply_search()
       via  8dc1552ce2a smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from create_file_unixpath()
       via  b87ada0acd7 smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from open_streams_for_delete()
       via  12a375df83b smbd: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from get_file_handle_for_metadata()
       via  15e52ebd028 net: remove NT_STATUS_STOPPED_ON_SYMLINK status code check from openat_pathref_fsp()
       via  ec89546b9b2 smbd: don't return NT_STATUS_STOPPED_ON_SYMLINK in openat_pathref_fsp()
       via  4b1918ca9a7 smbd: simplify error codepath in openat_pathref_fsp()
       via  95183a05af1 smbd: expect valid stat info in openat_pathref_fsp()
       via  19fe725a117 smbd: stat path before calling openat_pathref_fsp() in smbd_dirptr_get_entry()
       via  445b97d3168 smbd: move smb_fname creation to earlier point in smbd_dirptr_get_entry()
       via  821992641c3 smbd: stat path before calling openat_pathref_fsp() in open_pathref_base_fsp()
       via  5505b9a6834 smbd: remove a redundant fstat()in create_file_unixpath()
       via  2dff00e034a smbd: call stat before openat_pathref_fsp() in create_file_unixpath()
       via  af4737c4011 smbd: fix a resource leak in create_file_unixpath()
       via  589c10e91b9 smbd: stat path before calling openat_pathref_fsp() in unlink_internals()
       via  40583d313c3 s3/libadouble: stat path before calling openat_pathref_fsp() in ad_unconvert_open_ad()
       via  cfccd7792e1 VERSION: Bump version up to 4.14.6...
      from  852d0c036f0 VERSION: Disable GIT_SNAPSHOT for the 4.14.5 release.

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-14-stable


- Log -----------------------------------------------------------------
-----------------------------------------------------------------------

Summary of changes:
 VERSION                                     |   2 +-
 WHATSNEW.txt                                |  64 +++++-
 python/samba/netcmd/domain_backup.py        | 108 +++++-----
 python/samba/samdb.py                       | 105 ++++++++++
 python/samba/tests/domain_backup_offline.py | 162 ++++++++++++---
 python/samba/tests/dsdb.py                  | 305 +++++++++++++++++++++++++++-
 source3/lib/adouble.c                       |  13 +-
 source3/lib/filename_util.c                 |   2 +-
 source3/modules/vfs_default.c               |  58 +++++-
 source3/rpc_server/mdssvc/mdssvc.c          | 132 ++++++++++--
 source3/rpc_server/mdssvc/mdssvc.h          |   2 +
 source3/rpc_server/mdssvc/srv_mdssvc_nt.c   |   1 +
 source3/smbd/dir.c                          | 116 +++++------
 source3/smbd/dosmode.c                      |   3 -
 source3/smbd/filename.c                     |  15 +-
 source3/smbd/files.c                        |  99 ++++++---
 source3/smbd/msdfs.c                        |  54 ++++-
 source3/smbd/open.c                         |  79 ++++---
 source3/smbd/proto.h                        |  17 ++
 source3/smbd/reply.c                        |  34 ++--
 source3/smbd/smb2_close.c                   |   5 +-
 source3/smbd/smbXsrv_open.c                 |   9 +
 source3/smbd/smbXsrv_session.c              |   7 +
 source3/smbd/smbXsrv_tcon.c                 |   7 +
 source3/smbd/trans2.c                       |   3 -
 source3/utils/net_vfs.c                     |   3 -
 source4/auth/gensec/gensec_krb5.c           |   6 +-
 source4/selftest/tests.py                   |   2 +-
 28 files changed, 1132 insertions(+), 281 deletions(-)


Changeset truncated at 500 lines:

diff --git a/VERSION b/VERSION
index 45b88aa82a8..b5b81dc3eef 100644
--- a/VERSION
+++ b/VERSION
@@ -25,7 +25,7 @@
 ########################################################
 SAMBA_VERSION_MAJOR=4
 SAMBA_VERSION_MINOR=14
-SAMBA_VERSION_RELEASE=5
+SAMBA_VERSION_RELEASE=6
 
 ########################################################
 # If a official release has a serious bug              #
diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index 7a1af731a94..452eee13b54 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -1,3 +1,64 @@
+                   ==============================
+                   Release Notes for Samba 4.14.6
+                            July 13, 2021
+                   ==============================
+
+
+This is the latest stable release of the Samba 4.14 release series.
+
+
+Changes since 4.14.5
+--------------------
+
+o  Jeremy Allison <jra at samba.org>
+   * BUG 14722: s3: lib: Fix talloc heirarcy error in parent_smb_fname().
+   * BUG 14732: smbd: Fix pathref unlinking in create_file_unixpath().
+   * BUG 14734: s3: VFS: default: Add proc_fd's fallback for vfswrap_fchown().
+   * BUG 14736: s3: smbd: Remove erroneous TALLOC_FREE(smb_fname_parent) in
+     change_file_owner_to_parent() error path.
+
+o  Ralph Boehme <slow at samba.org>
+   * BUG 14730: NT_STATUS_FILE_IS_A_DIRECTORY error messages when using
+     glusterfs VFS module.
+   * BUG 14734: s3/modules: fchmod: Fallback to path based chmod if pathref.
+   * BUG 14740: Spotlight RPC service doesn't work with vfs_glusterfs.
+
+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.14.5
                             June 01, 2021
@@ -59,8 +120,7 @@ database (https://bugzilla.samba.org/).
 ======================================================================
 
 
-Release notes for older releases follow:
-----------------------------------------
+----------------------------------------------------------------------
 
 
                    ==============================
diff --git a/python/samba/netcmd/domain_backup.py b/python/samba/netcmd/domain_backup.py
index 799fd0593e5..f441e7407ee 100644
--- a/python/samba/netcmd/domain_backup.py
+++ b/python/samba/netcmd/domain_backup.py
@@ -62,50 +62,21 @@ from samba.credentials import SMB_SIGNING_REQUIRED
 # 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())
@@ -313,7 +284,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)
@@ -537,7 +509,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:
@@ -600,11 +573,12 @@ class cmd_domain_backup_restore(cmd_fsmo_seize):
                                        controls=["show_deleted:0",
                                                  "show_recycled:0"])
             except LdbError as dup_e:
-                if enum != ldb.ERR_NO_SUCH_OBJECT:
-                    raise e
+                (dup_enum, _) = dup_e.args
+                if dup_enum != ldb.ERR_NO_SUCH_OBJECT:
+                    raise
 
             if (len(dup_res) != 1):
-                raise e
+                raise
 
             objectguid = samdb.schema_format_value("objectGUID",
                                                        dup_res[0]["objectGUID"][0])
@@ -645,7 +619,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,
@@ -937,7 +912,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()
@@ -1025,7 +1001,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')
@@ -1050,7 +1027,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)
@@ -1102,9 +1079,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)))
@@ -1117,22 +1099,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.
                     if filename.endswith('.sock'):
                         continue
 
-                    all_files.append(os.path.join(working_dir, filename))
+                    all_files.append(full_path)
 
         # Backup secrets, sam.ldb and their downstream files
         self.backup_secrets(paths.private_dir, lp, logger)
@@ -1144,7 +1135,8 @@ class cmd_domain_backup_offline(samba.netcmd.Command):
         #          Writing to a .bak file only works because the DN being
         #          written to happens to be top level.
         samdb = SamDB(url=paths.samdb + self.backup_ext,
-                      session_info=system_session(), lp=lp)
+                      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", sid)
@@ -1156,7 +1148,7 @@ class cmd_domain_backup_offline(samba.netcmd.Command):
             if not os.path.exists(path + self.backup_ext):
                 if path.endswith('.ldb'):
                     logger.info('Starting transaction on solo db: ' + path)
-                    ldb_obj = Ldb(path, lp=lp)
+                    ldb_obj = Ldb(path, lp=lp, flags=ldb.FLG_DONT_CREATE_DB)
                     ldb_obj.transaction_start()
                     logger.info('   running tdbbackup on the same file')
                     self.offline_tdb_copy(path)
diff --git a/python/samba/samdb.py b/python/samba/samdb.py
index f95709ab7c8..d65c6f2e3b1 100644
--- a/python/samba/samdb.py
+++ b/python/samba/samdb.py
@@ -1385,6 +1385,111 @@ schemaUpdateNow: 1
         '''return a new RID from the RID Pool on this DSA'''
         return dsdb._dsdb_allocate_rid(self)
 
+    def next_free_rid(self):
+        '''return the next free RID from the RID Pool on this DSA.
+
+        :note: This function is not intended for general use, and care must be
+            taken if it is used to generate objectSIDs. The returned RID is not
+            formally reserved for use, creating the possibility of duplicate
+            objectSIDs.
+        '''
+        rid, _ = self.free_rid_bounds()
+        return rid
+
+    def free_rid_bounds(self):
+        '''return the low and high bounds (inclusive) of RIDs that are
+            available for use in this DSA's current RID pool.
+
+        :note: This function is not intended for general use, and care must be
+            taken if it is used to generate objectSIDs. The returned range of
+            RIDs is not formally reserved for use, creating the possibility of
+            duplicate objectSIDs.
+        '''
+        # Get DN of this server's RID Set
+        server_name_dn = ldb.Dn(self, self.get_serverName())
+        res = self.search(base=server_name_dn,
+                          scope=ldb.SCOPE_BASE,
+                          attrs=["serverReference"])
+        try:
+            server_ref = res[0]["serverReference"]
+        except KeyError:
+            raise ldb.LdbError(
+                ldb.ERR_NO_SUCH_ATTRIBUTE,
+                "No RID Set DN - "
+                "Cannot find attribute serverReference of %s "
+                "to calculate reference dn" % server_name_dn) from None
+        server_ref_dn = ldb.Dn(self, server_ref[0].decode("utf-8"))
+
+        res = self.search(base=server_ref_dn,
+                          scope=ldb.SCOPE_BASE,
+                          attrs=["rIDSetReferences"])
+        try:
+            rid_set_refs = res[0]["rIDSetReferences"]
+        except KeyError:
+            raise ldb.LdbError(
+                ldb.ERR_NO_SUCH_ATTRIBUTE,
+                "No RID Set DN - "
+                "Cannot find attribute rIDSetReferences of %s "
+                "to calculate reference dn" % server_ref_dn) from None
+        rid_set_dn = ldb.Dn(self, rid_set_refs[0].decode("utf-8"))
+
+        # Get the alloc pools and next RID of this RID Set
+        res = self.search(base=rid_set_dn,
+                          scope=ldb.SCOPE_BASE,
+                          attrs=["rIDAllocationPool",
+                                 "rIDPreviousAllocationPool",
+                                 "rIDNextRID"])
+
+        uint32_max = 2**32 - 1
+        uint64_max = 2**64 - 1
+
+        try:
+            alloc_pool = int(res[0]["rIDAllocationPool"][0])
+        except KeyError:
+            alloc_pool = uint64_max
+        if alloc_pool == uint64_max:
+            raise ldb.LdbError(ldb.ERR_OPERATIONS_ERROR,
+                               "Bad RID Set %s" % rid_set_dn)
+
+        try:
+            prev_pool = int(res[0]["rIDPreviousAllocationPool"][0])
+        except KeyError:
+            prev_pool = uint64_max
+        try:
+            next_rid = int(res[0]["rIDNextRID"][0])
+        except KeyError:
+            next_rid = uint32_max
+
+        # If we never used a pool, set up our first pool
+        if prev_pool == uint64_max or next_rid == uint32_max:
+            prev_pool = alloc_pool
+            next_rid = prev_pool & uint32_max
+
+        next_rid += 1
+
+        # Now check if our current pool is still usable
+        prev_pool_lo = prev_pool & uint32_max
+        prev_pool_hi = prev_pool >> 32
+        if next_rid > prev_pool_hi:
+            # We need a new pool, check if we already have a new one
+            # Otherwise we return an error code.
+            if alloc_pool == prev_pool:
+                raise ldb.LdbError(ldb.ERR_OPERATIONS_ERROR,
+                                   "RID pools out of RIDs")
+
+            # Now use the new pool
+            prev_pool = alloc_pool
+            prev_pool_lo = prev_pool & uint32_max
+            prev_pool_hi = prev_pool >> 32
+            next_rid = prev_pool_lo
+
+        if next_rid < prev_pool_lo or next_rid > prev_pool_hi:
+            raise ldb.LdbError(ldb.ERR_OPERATIONS_ERROR,
+                               "Bad RID chosen %d from range %d-%d" %
+                               (next_rid, prev_pool_lo, prev_pool_hi))
+
+        return next_rid, prev_pool_hi
+
     def normalize_dn_in_domain(self, dn):
         '''return a new DN expanded by adding the domain DN
 
diff --git a/python/samba/tests/domain_backup_offline.py b/python/samba/tests/domain_backup_offline.py
index 8b7209ec24d..21f42c6dab8 100644
--- a/python/samba/tests/domain_backup_offline.py
+++ b/python/samba/tests/domain_backup_offline.py
@@ -19,8 +19,12 @@ import tarfile
 import os
 import shutil
 import tempfile
-from samba.tests import BlackboxTestCase
+from samba.tests import BlackboxTestCase, BlackboxProcessError
 from samba.netcmd import CommandError
+from samba.param import LoadParm
+from samba.join import join_DC
+from samba.credentials import Credentials
+from samba.logger import get_samba_logger
 
 # The backup tests require that a completely clean LoadParm object gets used
 # for the restore. Otherwise the same global LP gets re-used, and the LP
@@ -31,6 +35,81 @@ from samba.netcmd import CommandError
 # so that we never inadvertently use .runcmd() by accident.
 class DomainBackupOfflineCmp(BlackboxTestCase):
 
+    def test_domain_backup_offline_nested_tdb(self):
+        self.nested_testcase('tdb')
+
+    def test_domain_backup_offline_nested_mdb(self):
+        self.nested_testcase('mdb')
+
+    def nested_testcase(self, backend):
+        self.prov_dir = self.provision(backend)
+        self.extract_dir = None
+
+        src = os.path.join(self.prov_dir, "private")
+        dst = os.path.join(self.prov_dir, "state", "private")
+
+        # Move private directory inside state directory
+        shutil.move(src, dst)
+
+        smbconf = os.path.join(self.prov_dir, "etc", "smb.conf")
+
+        # Update the conf file
+        lp = LoadParm(filename_for_non_global_lp=smbconf)
+        lp.set("private dir", dst)
+        lp.dump(False, smbconf)
+
+        backup_file = self.backup(self.prov_dir)
+
+        # Ensure each file is only present once in the tar file
+        tf = tarfile.open(backup_file)
+        names = tf.getnames()
+        self.assertEqual(len(names), len(set(names)))
+
+    def test_domain_backup_offline_join_restore_tdb(self):
+        self.join_restore_testcase('tdb')
+
+    def test_domain_backup_offline_join_restore_mdb(self):
+        self.join_restore_testcase('mdb')
+
+    def join_restore_testcase(self, backend):
+        self.prov_dir = self.join(backend)
+        self.extract_dir = None
+
+        try:
+            backup_file = self.backup(self.prov_dir)
+        except BlackboxProcessError as e:
+            self.fail(e)
+
+        self.extract_dir = self.restore(backup_file)
+
+    def test_domain_backup_offline_hard_link_tdb(self):
+        self.hard_link_testcase('tdb')
+
+    def test_domain_backup_offline_hard_link_mdb(self):
+        self.hard_link_testcase('mdb')
+
+    def hard_link_testcase(self, backend):
+        self.prov_dir = self.provision(backend)
+        self.extract_dir = None


-- 
Samba Shared Repository



More information about the samba-cvs mailing list