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

Karolin Seeger kseeger at samba.org
Mon Jul 12 13:53:02 UTC 2021


The branch, v4-14-test has been updated
       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().
      from  42fa9f800fd smbd: fix pathref unlinking in create_file_unixpath()

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


- Log -----------------------------------------------------------------
commit 8f7ab597969e6e834ef333d5cf314f770325d6a9
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Jul 5 17:17:30 2021 +0200

    smbXsrv_{open,session,tcon}: protect smbXsrv_{open,session,tcon}_global_traverse_fn against invalid records
    
    I saw systems with locking.tdb records being part of:
      ctdb catdb smbXsrv_tcon_global.tdb
    
    It's yet unknown how that happened, but we should not panic in srvsvc_*
    calls because the info0 pointer was NULL.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14752
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Volker Lendecke <vl at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Tue Jul  6 11:08:43 UTC 2021 on sn-devel-184
    
    (cherry picked from commit 00bab5b3c821f272153a25ded9743460887a7907)
    
    Autobuild-User(v4-14-test): Karolin Seeger <kseeger at samba.org>
    Autobuild-Date(v4-14-test): Mon Jul 12 13:52:06 UTC 2021 on sn-devel-184

commit c1662a8122011aa550b2ae2325de97c6f57e1485
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Jul 2 09:37:25 2021 +0200

    gensec_krb5: restore ipv6 support for kpasswd
    
    We need to offer as much space we have in order to
    get the address out of tsocket_address_bsd_sockaddr().
    
    This fixes a regression in commit
    43c808f2ff907497dfff0988ff90a48fdcfc16ef.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14750
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    (cherry picked from commit 0388a8f33bdde49f1cc805a0291859203c1a52b4)

commit a6447a1dce1bed1a33ab6aa729f5837acc3895f6
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Thu May 27 15:35:35 2021 +1200

    netcmd: Use next_free_rid() function to calculate a SID for restoring a backup
    
    This means we won't get errors if the DC doesn't have a rIDNextRID
    attribute, but we will still error if there is no RID Set or if all its
    pools are exhausted.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14669
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    (cherry picked from commit 59d293b60608172ae61551c642d13d3b215924e4)

commit 69d8b64fdc1b2d9b5ac88385af704e2935d6ca4e
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Mon May 24 16:46:28 2021 +1200

    python/tests/dsdb: Add tests for RID allocation functions
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14669
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    (cherry picked from commit 7c7cad81844950c3efe9a540a47b9d4e1ce1b2a1)

commit 94ca97bd121993b461082286ae24d2510211d36e
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Mon May 24 12:59:59 2021 +1200

    dsdb: Add next_free_rid() function to allocate a RID without modifying the database
    
    If used to generate SIDs for objects, care should be taken, as the
    possibility for having duplicate objectSIDs can arise.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14669
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    (cherry picked from commit cc98e03e7a0f2bf7a1ace2950fe6500f53640c1b)

commit f9d2652a0b42c37acff3ce16f0c430f3522012e5
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Mon May 24 14:58:40 2021 +1200

    netcmd: Add tests for performing an offline backup immediately after joining a domain
    
    This currently fails due to the DC not having a rIDNextRID attribute,
    which is required for the restore process.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14669
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    (cherry picked from commit b7e6a1c5da7283c49586dc29f85ab19e0e57b0f6)

commit b226e83a3dc3c74c06e48469ec02c19cbbfb963b
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Wed May 26 13:40:30 2021 +1200

    netcmd: Ignore rIDUsedPool attribute in offline domain backup test
    
    The RID Set of the newly created DC account has all its values
    initialised to zero. If the rIDUsedPool attribute was previously
    non-zero, then the restore process will cause its value to change.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14669
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    (cherry picked from commit 658e5a6cc20b57f48477affd370fe25458178b92)

commit 79029224ee02ff9f240ab1a81a3372a193b0879d
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Mon May 24 16:40:55 2021 +1200

    netcmd: Fix error-checking condition
    
    This condition probably meant to check the argument of the most recently
    thrown exception, rather than the previous one again.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14669
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    (cherry picked from commit e8c242bed19432d96e78dc345ab5f06422c5b104)

commit c1ac591c1976278aac7c26f91d87acdf37bdfb77
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Tue Mar 16 22:20:21 2021 +1300

    netcmd: Avoid database corruption by opting not to create database files during an offline domain backup
    
    If backup dirs contain hardlinks, the backup process could previously
    attempt to open an LMDB database already opened during the backup,
    causing it to be recreated as a new TDB database. This commit ensures
    that new database files are not created during this operation, and that
    the main SamDB database is not modified.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14027
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    (cherry picked from commit 4cf773591d49166b8c7ef8d637d7edfe755d48aa)

commit 7a7bfba1d981edca2dc54db9c43c7f6b9310bc39
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Tue Mar 16 16:22:40 2021 +1300

    netcmd: Determine which files are to be copied for an offline domain backup
    
    The old behaviour attempted to check for and remove files with duplicate
    names, but did not do so due to a bug, and would have left undetermined
    which files were given priority when duplicate filenames were present.
    Now when hardlinks are present, only one instance of each file is
    chosen, with files in the private directory having priority. If one
    backup dir is nested inside another, the files contained in the nested
    directory are only added once. Additionally, the BIND DNS database is
    omitted from the backup.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14027
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    (cherry picked from commit 3723148e7aa7e6d4a48a1a38112f121f52b6ee6f)

commit 5b361227e7cd259b5585b4e9ad0df7ccd1021580
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Thu Mar 18 10:52:52 2021 +1300

    netcmd: Add test for an offline backup of nested directories
    
    This test verifies that when performing an offline backup of a domain
    where one of the directories to be backed up is nested inside another,
    the contained files are only included once in the backup.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14027
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    (cherry picked from commit f994783f4279884ec4d2ee3e7db80fb7af267d1c)

commit b095932a303c881b459ba73e222b6ed199f673dc
Author: Joseph Sutton <josephsutton at catalyst.net.nz>
Date:   Tue Mar 16 16:13:05 2021 +1300

    netcmd: Add test for an offline backup of a directory containing hardlinks
    
    This test verifies that when performing an offline backup of a domain
    where the directories to be backed up contain hardlinks, only one
    instance of each file is backed up, and that files in the private
    directory take precedence.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14027
    
    Signed-off-by: Joseph Sutton <josephsutton at catalyst.net.nz>
    (cherry picked from commit 0e5738887524b467bfebcf657bcb00ed71827784)

commit 60714069b2c8550de7527336713f8e8905c5869b
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 10 12:34:32 2021 +0200

    mdssvc: avoid direct filesystem access, use the VFS
    
    This ensures mdssvc uses the same FileIDs as the fileserver as well as Spotlight
    can be used working on a virtual filesystem like GlusterFS.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14740
    RN: Spotlight RPC service doesn't work with vfs_glusterfs
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Ralph Böhme <slow at samba.org>
    Autobuild-Date(master): Wed Jun 16 05:59:13 UTC 2021 on sn-devel-184
    
    (backported from commit 620b99144359f45aa69c13731db8d793cfbba197)
    [slow at samba.org: smbd_check_access_rights_fsp() doesn't take dirfsp arg]

commit 1911547725601a728617e0677486a78ed99e4169
Author: Ralph Boehme <slow at samba.org>
Date:   Tue Jun 15 14:14:52 2021 +0200

    mdssvc: chdir() to the conn of the RPC request
    
    In preperation of calling VFS functions.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14740
    
    Reviewed-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 6de3a88494b5932d0fd10f5c8c8ec57916aeefc5)

commit f8e857aeed30bc2c42f42c8692ce207a3f2d4a19
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 10 12:10:08 2021 +0200

    mdssvc: maintain a connection struct in the mds_ctx
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14740
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 8b681cfb5d9b1ece03f7e7b9d3a08ae6c461d679)

commit 9439cfe71422d8f29e5b998ff5b1007de6dcec8c
Author: Ralph Boehme <slow at samba.org>
Date:   Fri May 28 09:25:22 2021 +0200

    smbd: add create_conn_struct_cwd()
    
    Compared to create_conn_struct_tos_cwd() this takes a TALLOC_CTX and
    tevent_context as additional arguments and the resulting connection_struct is
    stable across the lifetime of mem_ctx and ev.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14740
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 9a2d6bcfd5797dd4db764921548c8dca6dd0eb21)

commit 5ee1c6a0b01d03c0d697bd797474b0d35e49b512
Author: Ralph Boehme <slow at samba.org>
Date:   Tue Jun 15 11:17:57 2021 +0200

    smbd: pass tevent context to create_conn_struct_as_root()
    
    The next commit will add another caller of create_conn_struct_as_root() that is
    going to pass a long-lived tevent context.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14740
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 16c39b81d6f2c7d75cfe72bbbe2f6a5bde42c7b0)

commit b1cb178ab9de83bfee55f8a7145a978bb736feed
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 10 12:08:17 2021 +0200

    mdssvc: pass messaging context to mds_init_ctx()
    
    This is needed in a subsequent commit. Note that I prefer to do the event
    context unwrapping in the caller and pass both the event and messaging context
    explicitly to mds_init_ctx().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14740
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 1ef2828e1025e4c89292df1dfa6161c4453b3afe)

commit db5326a7f7a0ba877b0b21685fa825b2794dce81
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 10 11:07:27 2021 +0200

    mdssvc: don't fail mds_add_result() if result is not found in CNID set
    
    Just skip adding the result to the pending results set, don't return an
    error. Returning an error triggers an error at the MDSSVC RPC error which is NOT
    what we want here.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14740
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 8847f46f75ac5c1a753a0e7da88c522be25ef681)

commit 6ce42a067f34d40e5c26712413405f591a3b7b67
Author: Ralph Boehme <slow at samba.org>
Date:   Mon May 10 11:04:38 2021 +0200

    mdssvc: use a helper variable in mds_add_result()
    
    No change in behaviour.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14740
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit e2486d76b611f07b85b26c54fe14da7b76bd01c2)

commit 858a116e796e35bbe52ff4e60cdeb255c408b497
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Jan 21 15:04:57 2021 +0100

    smbd: add synthetic_pathref()
    
    Similar to synthetic_smb_fname(), but also opens a pathref fsp.
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit d9f95b8cefe2d1c8020592434481025aa1045e2f)

commit 4936ad998598325f1b472d7ecb2af82c08a1ef8f
Author: Jeremy Allison <jra at samba.org>
Date:   Wed Jun 9 12:22:26 2021 -0700

    s3: smbd: Remove erroneous TALLOC_FREE(smb_fname_parent) in change_file_owner_to_parent() error path.
    
    Caller is still using this !
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14736
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Noel Power<npower at samba.org>
    
    Autobuild-User(master): Noel Power <npower at samba.org>
    Autobuild-Date(master): Fri Jun 11 10:17:46 UTC 2021 on sn-devel-184
    
    (cherry picked from commit 4f20d310af2bb1f96dea4810a7130492cc4cfc55)

commit f8c4bcb0b22d3c20419bec2f175785266e629f3a
Author: Ralph Boehme <slow at samba.org>
Date:   Fri Apr 9 14:58:34 2021 +0200

    s3/modules: fchmod: fallback to path based chmod if pathref
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14734
    
    Signed-off-by: Noel Power <noel.power at suse.com>
    Signed-off-by: Ralph Boehme <slow at samba.org>
    
    Back-ported from master commit 6ad10836d6e04d8c95773e9122b63f5a5e040487)

commit 866efccfa9061a5b3468af74fc5d0791feffa5fa
Author: Jeremy Allison <jra at samba.org>
Date:   Wed Jun 9 15:57:38 2021 -0700

    s3: VFS: default: Add proc_fd's fallback for vfswrap_fchown().
    
    https://bugzilla.samba.org/show_bug.cgi?id=14734
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Noel Power <npower at samba.org>
    
    Autobuild-User(master): Noel Power <npower at samba.org>
    Autobuild-Date(master): Thu Jun 10 09:16:22 UTC 2021 on sn-devel-184
    
    (cherry picked from commit f44918e6c83c89936156eb24c982a897c9c45f61)

commit 35d7a23d72054363ec659b1d89e2e6fbd850a7a3
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Jun 1 13:27:47 2021 -0700

    s3: lib: Fix talloc heirarcy error in parent_smb_fname().
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14722
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit c500d99e2f5aaec102bf952b7941a2596b3e35a1)

-----------------------------------------------------------------------

Summary of changes:
 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/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/files.c                        |  52 +++++
 source3/smbd/msdfs.c                        |  54 ++++-
 source3/smbd/open.c                         |   2 -
 source3/smbd/proto.h                        |  17 ++
 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 +-
 18 files changed, 913 insertions(+), 118 deletions(-)


Changeset truncated at 500 lines:

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
+
+        # Create hard links in the private and state directories
+        os.link(os.path.join(self.prov_dir, "private", "krb5.conf"),
+                os.path.join(self.prov_dir, "state", "krb5.conf"))
+
+        backup_file = self.backup(self.prov_dir)
+
+        # Extract the backup
+        self.extract_dir = tempfile.mkdtemp(dir=self.tempdir)
+        tf = tarfile.open(backup_file)
+        tf.extractall(self.extract_dir)
+
+        # Ensure that the hard link in the private directory was backed up,
+        # while the one in the state directory was not.
+        self.assertTrue(os.path.exists(os.path.join(self.extract_dir,
+                                                    "private", "krb5.conf")))
+        self.assertFalse(os.path.exists(os.path.join(self.extract_dir,
+                                                    "statedir", "krb5.conf")))
+
     def test_domain_backup_offline_untar_tdb(self):
         self.untar_testcase('tdb')
 
@@ -44,39 +123,33 @@ class DomainBackupOfflineCmp(BlackboxTestCase):
         self.restore_testcase('mdb')
 
     def restore_testcase(self, backend):
-        prov_dir, backup_file = self.provision_and_backup(backend)
+        self.prov_dir = self.provision(backend)
+        self.extract_dir = None
+        backup_file = self.backup(self.prov_dir)
 
-        extract_dir = tempfile.mkdtemp(dir=self.tempdir)
-        cmd = ("samba-tool domain backup restore --backup-file={f}"
-               " --targetdir={d} "
-               "--newservername=NEWSERVER").format(f=backup_file, d=extract_dir)
-        self.check_output(cmd)
+        self.extract_dir = self.restore(backup_file)
 
         # attrs that are altered by the restore process
         ignore_attrs = ["servicePrincipalName", "lastLogonTimestamp",
-                        "rIDAllocationPool", "rIDAvailablePool",
+                        "rIDAllocationPool", "rIDAvailablePool", "rIDUsedPool",
                         "localPolicyFlags", "operatingSystem", "displayName",
                         "dnsRecord", "dNSTombstoned",
                         "msDS-NC-Replica-Locations", "msDS-HasInstantiatedNCs",
                         "interSiteTopologyGenerator"]
         filter_arg = "--filter=" + ",".join(ignore_attrs)
         args = ["--two", filter_arg]
-        self.ldapcmp(prov_dir, extract_dir, args)
-
-        shutil.rmtree(prov_dir)
-        shutil.rmtree(extract_dir)
+        self.ldapcmp(self.prov_dir, self.extract_dir, args)
 
     def untar_testcase(self, backend):
-        prov_dir, backup_file = self.provision_and_backup(backend)
+        self.prov_dir = self.provision(backend)
+        self.extract_dir = None
+        backup_file = self.backup(self.prov_dir)
 
-        extract_dir = tempfile.mkdtemp(dir=self.tempdir)
+        self.extract_dir = tempfile.mkdtemp(dir=self.tempdir)
         tf = tarfile.open(backup_file)
-        tf.extractall(extract_dir)
-
-        self.ldapcmp(prov_dir, extract_dir)
+        tf.extractall(self.extract_dir)
 
-        shutil.rmtree(prov_dir)
-        shutil.rmtree(extract_dir)
+        self.ldapcmp(self.prov_dir, self.extract_dir)
 
     def ldapcmp(self, prov_dir, ex_dir, args=[]):
         sam_fn = os.path.join("private", "sam.ldb")
@@ -90,8 +163,8 @@ class DomainBackupOfflineCmp(BlackboxTestCase):
             self.check_output(cmd)
 
     # Test the "samba-tool domain backup" command with ldapcmp
-    def provision_and_backup(self, backend):
-        prov_dir = tempfile.mkdtemp(dir=self.tempdir)
+    def provision(self, backend):
+        target = tempfile.mkdtemp(dir=self.tempdir)
 
         # Provision domain.  Use fake ACLs and store xattrs in tdbs so that
         # NTACL backup will work inside the testenv.
@@ -100,13 +173,37 @@ class DomainBackupOfflineCmp(BlackboxTestCase):
         # circumstances, causing the ldapcmp to fail.
         prov_cmd = "samba-tool domain provision " +\
                    "--domain FOO --realm foo.example.com " +\
-                   "--targetdir {prov_dir} " +\
+                   "--targetdir {target} " +\
                    "--backend-store {backend} " +\


-- 
Samba Shared Repository



More information about the samba-cvs mailing list