[SCM] Samba Shared Repository - branch master updated

Andreas Schneider asn at samba.org
Mon Jan 22 16:49:01 UTC 2024


The branch, master has been updated
       via  8579340fc54 gpo: Do not get templates list on first run
       via  3f3ddfa699a gpo: Decode base64 root cert before importing
       via  0d1ff69936f gpo: Test certificate policy without NDES
      from  2713023250f smbd: use dirfsp and atname in open_directory()

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 8579340fc540633c13c017d896034904a8dbd55c
Author: Gabriel Nagy <gabriel.nagy at canonical.com>
Date:   Fri Jan 19 11:36:19 2024 +0200

    gpo: Do not get templates list on first run
    
    This is a visual fix and has no impact on functionality apart from
    cleaner log messages.
    
    The point of this is to get the list of supported templates in order to
    compute a diff between the current applied templates and the updated
    list, so we are able to unapply and reapply the policy in case there are
    differences.
    
    However this code path is executed on first applies as well, at which
    point the root CA is not yet set up. This causes the
    `get_supported_templates` call to fail, which is not a hard failure but
    still pollutes the logs. In this case it's safe to avoid executing the
    command as the policy will be applied regardless.
    
    Signed-off-by: Gabriel Nagy <gabriel.nagy at canonical.com>
    Reviewed-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>
    
    Autobuild-User(master): Andreas Schneider <asn at cryptomilk.org>
    Autobuild-Date(master): Mon Jan 22 16:48:57 UTC 2024 on atb-devel-224

commit 3f3ddfa699a33c2c8a59f7fb9ee044bb2a6e0e06
Author: Gabriel Nagy <gabriel.nagy at canonical.com>
Date:   Thu Jan 18 20:23:24 2024 +0200

    gpo: Decode base64 root cert before importing
    
    The reasoning behind this is described in the previous commit message,
    but essentially this should either be wrapped in certificate blocks and
    imported as PEM, or converted back to binary and imported as DER.
    
    I've opted for the latter since it's how it used to work before it
    regressed in 157335ee93e.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15557
    
    Signed-off-by: Gabriel Nagy <gabriel.nagy at canonical.com>
    Reviewed-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>

commit 0d1ff69936f18ea729fc11fbbb1569a833302572
Author: Gabriel Nagy <gabriel.nagy at canonical.com>
Date:   Mon Jan 8 18:05:08 2024 +0200

    gpo: Test certificate policy without NDES
    
    As of 8231eaf856b, the NDES feature is no longer required on Windows, as
    cert auto-enroll can use the certificate from the LDAP request.
    
    However, 157335ee93e changed the implementation to convert the LDAP
    certificate to base64 due to it failing to cleanly convert to a string.
    
    Because of insufficient test coverage I missed handling the part where
    NDES is disabled or not reachable and the LDAP certificate was imported.
    The call to load_der_x509_certificate now fails with an error because it
    expects binary data, yet it receives a base64 encoded string.
    
    This adds a test to confirm the issue.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15557
    
    Signed-off-by: Gabriel Nagy <gabriel.nagy at canonical.com>
    Reviewed-by: David Mulder <dmulder at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>

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

Summary of changes:
 python/samba/gp/gp_cert_auto_enroll_ext.py |   8 +-
 python/samba/tests/gpo.py                  | 126 +++++++++++++++++++++++++++--
 2 files changed, 125 insertions(+), 9 deletions(-)


Changeset truncated at 500 lines:

diff --git a/python/samba/gp/gp_cert_auto_enroll_ext.py b/python/samba/gp/gp_cert_auto_enroll_ext.py
index e2f81b3f3f8..8ba1960efe5 100644
--- a/python/samba/gp/gp_cert_auto_enroll_ext.py
+++ b/python/samba/gp/gp_cert_auto_enroll_ext.py
@@ -217,10 +217,11 @@ def getca(ca, url, trust_dir):
                  ' installed or not configured.')
         if 'cACertificate' in ca:
             log.warn('Installing the server certificate only.')
+            der_certificate = base64.b64decode(ca['cACertificate'])
             try:
-                cert = load_der_x509_certificate(ca['cACertificate'])
+                cert = load_der_x509_certificate(der_certificate)
             except TypeError:
-                cert = load_der_x509_certificate(ca['cACertificate'],
+                cert = load_der_x509_certificate(der_certificate,
                                                  default_backend())
             cert_data = cert.public_bytes(Encoding.PEM)
             with open(root_cert, 'wb') as w:
@@ -358,7 +359,8 @@ class gp_cert_auto_enroll_ext(gp_pol_ext, gp_applier):
         # If the policy has changed, unapply, then apply new policy
         old_val = self.cache_get_attribute_value(guid, attribute)
         old_data = json.loads(old_val) if old_val is not None else {}
-        templates = ['%s.%s' % (ca['name'], t.decode()) for t in get_supported_templates(ca['hostname'])]
+        templates = ['%s.%s' % (ca['name'], t.decode()) for t in get_supported_templates(ca['hostname'])] \
+            if old_val is not None else []
         new_data = { 'templates': templates, **ca }
         if changed(new_data, old_data) or self.cache_get_apply_state() == GPOSTATE.ENFORCE:
             self.unapply(guid, attribute, old_val)
diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py
index 81bf3b8c03b..9177eef5afa 100644
--- a/python/samba/tests/gpo.py
+++ b/python/samba/tests/gpo.py
@@ -103,17 +103,21 @@ def dummy_certificate():
 
 # Dummy requests structure for Certificate Auto Enrollment
 class dummy_requests(object):
-    @staticmethod
-    def get(url=None, params=None):
+    class exceptions(object):
+        ConnectionError = Exception
+
+    def __init__(self, want_exception=False):
+        self.want_exception = want_exception
+
+    def get(self, url=None, params=None):
+        if self.want_exception:
+            raise self.exceptions.ConnectionError
+
         dummy = requests.Response()
         dummy._content = dummy_certificate()
         dummy.headers = {'Content-Type': 'application/x-x509-ca-cert'}
         return dummy
 
-    class exceptions(object):
-        ConnectionError = Exception
-cae.requests = dummy_requests
-
 realm = os.environ.get('REALM')
 policies = realm + '/POLICIES'
 realm = realm.lower()
@@ -6906,6 +6910,114 @@ class GPOTests(tests.TestCase):
         # Unstage the Registry.pol file
         unstage_file(reg_pol)
 
+    def test_gp_cert_auto_enroll_ext_without_ndes(self):
+        local_path = self.lp.cache_path('gpo_cache')
+        guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}'
+        reg_pol = os.path.join(local_path, policies, guid,
+                               'MACHINE/REGISTRY.POL')
+        cache_dir = self.lp.get('cache directory')
+        store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
+
+        machine_creds = Credentials()
+        machine_creds.guess(self.lp)
+        machine_creds.set_machine_account()
+
+        # Initialize the group policy extension
+        cae.requests = dummy_requests(want_exception=True)
+        ext = cae.gp_cert_auto_enroll_ext(self.lp, machine_creds,
+                                          machine_creds.get_username(), store)
+
+        gpos = get_gpo_list(self.server, machine_creds, self.lp,
+                            machine_creds.get_username())
+
+        # Stage the Registry.pol file with test data
+        parser = GPPolParser()
+        parser.load_xml(etree.fromstring(auto_enroll_reg_pol.strip()))
+        ret = stage_file(reg_pol, ndr_pack(parser.pol_file))
+        self.assertTrue(ret, 'Could not create the target %s' % reg_pol)
+
+        # Write the dummy CA entry, Enrollment Services, and Templates Entries
+        admin_creds = Credentials()
+        admin_creds.set_username(os.environ.get('DC_USERNAME'))
+        admin_creds.set_password(os.environ.get('DC_PASSWORD'))
+        admin_creds.set_realm(os.environ.get('REALM'))
+        hostname = get_dc_hostname(machine_creds, self.lp)
+        url = 'ldap://%s' % hostname
+        ldb = Ldb(url=url, session_info=system_session(),
+                  lp=self.lp, credentials=admin_creds)
+        # Write the dummy CA
+        confdn = 'CN=Public Key Services,CN=Services,CN=Configuration,%s' % base_dn
+        ca_cn = '%s-CA' % hostname.replace('.', '-')
+        certa_dn = 'CN=%s,CN=Certification Authorities,%s' % (ca_cn, confdn)
+        ldb.add({'dn': certa_dn,
+                 'objectClass': 'certificationAuthority',
+                 'authorityRevocationList': ['XXX'],
+                 'cACertificate': dummy_certificate(),
+                 'certificateRevocationList': ['XXX'],
+                })
+        # Write the dummy pKIEnrollmentService
+        enroll_dn = 'CN=%s,CN=Enrollment Services,%s' % (ca_cn, confdn)
+        ldb.add({'dn': enroll_dn,
+                 'objectClass': 'pKIEnrollmentService',
+                 'cACertificate': dummy_certificate(),
+                 'certificateTemplates': ['Machine'],
+                 'dNSHostName': hostname,
+                })
+        # Write the dummy pKICertificateTemplate
+        template_dn = 'CN=Machine,CN=Certificate Templates,%s' % confdn
+        ldb.add({'dn': template_dn,
+                 'objectClass': 'pKICertificateTemplate',
+                })
+
+        with TemporaryDirectory() as dname:
+            try:
+                ext.process_group_policy([], gpos, dname, dname)
+            except Exception as e:
+                self.fail(str(e))
+
+            ca_crt = os.path.join(dname, '%s.crt' % ca_cn)
+            self.assertTrue(os.path.exists(ca_crt),
+                            'Root CA certificate was not requested')
+            machine_crt = os.path.join(dname, '%s.Machine.crt' % ca_cn)
+            self.assertTrue(os.path.exists(machine_crt),
+                            'Machine certificate was not requested')
+            machine_key = os.path.join(dname, '%s.Machine.key' % ca_cn)
+            self.assertTrue(os.path.exists(machine_key),
+                            'Machine key was not generated')
+
+            # Verify RSOP does not fail
+            ext.rsop([g for g in gpos if g.name == guid][0])
+
+            # Check that a call to gpupdate --rsop also succeeds
+            ret = rsop(self.lp)
+            self.assertEqual(ret, 0, 'gpupdate --rsop failed!')
+
+            # Remove policy
+            gp_db = store.get_gplog(machine_creds.get_username())
+            del_gpos = get_deleted_gpos_list(gp_db, [])
+            ext.process_group_policy(del_gpos, [], dname)
+            self.assertFalse(os.path.exists(ca_crt),
+                            'Root CA certificate was not removed')
+            self.assertFalse(os.path.exists(machine_crt),
+                            'Machine certificate was not removed')
+            self.assertFalse(os.path.exists(machine_key),
+                            'Machine key was not removed')
+            out, _ = Popen(['getcert', 'list-cas'], stdout=PIPE).communicate()
+            self.assertNotIn(get_bytes(ca_cn), out, 'CA was not removed')
+            out, _ = Popen(['getcert', 'list'], stdout=PIPE).communicate()
+            self.assertNotIn(b'Machine', out,
+                             'Machine certificate not removed')
+            self.assertNotIn(b'Workstation', out,
+                             'Workstation certificate not removed')
+
+        # Remove the dummy CA, pKIEnrollmentService, and pKICertificateTemplate
+        ldb.delete(certa_dn)
+        ldb.delete(enroll_dn)
+        ldb.delete(template_dn)
+
+        # Unstage the Registry.pol file
+        unstage_file(reg_pol)
+
     def test_gp_cert_auto_enroll_ext(self):
         local_path = self.lp.cache_path('gpo_cache')
         guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}'
@@ -6919,6 +7031,7 @@ class GPOTests(tests.TestCase):
         machine_creds.set_machine_account()
 
         # Initialize the group policy extension
+        cae.requests = dummy_requests()
         ext = cae.gp_cert_auto_enroll_ext(self.lp, machine_creds,
                                           machine_creds.get_username(), store)
 
@@ -7517,6 +7630,7 @@ class GPOTests(tests.TestCase):
         machine_creds.set_machine_account()
 
         # Initialize the group policy extension
+        cae.requests = dummy_requests()
         ext = cae.gp_cert_auto_enroll_ext(self.lp, machine_creds,
                                           machine_creds.get_username(), store)
 


-- 
Samba Shared Repository



More information about the samba-cvs mailing list