The branch, master has been updated
       via  eb2e779 samdb/cracknames: support user and service principal as 
desired format
       via  c186e02 samdb/cracknames: do not show recycled when a guid is 
desired
       via  4779afe python/tests: add python test for cracknames
      from  61455ad selftest: Make --include-env and --exclude-env use the base 
env name

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


- Log -----------------------------------------------------------------
commit eb2e77970e41c1cb62c041877565e939c78ff52d
Author: Bob Campbell <bobcampb...@catalyst.net.nz>
Date:   Wed Jul 5 16:08:11 2017 +1200

    samdb/cracknames: support user and service principal as desired format
    
    This adds support for DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL and
    DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL as desired formats.
    
    This also causes the test in cracknames.py to no longer fail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12842
    
    Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Garming Sam <garm...@catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abart...@samba.org>
    Autobuild-Date(master): Mon Jul 24 11:10:26 CEST 2017 on sn-devel-144

commit c186e02b40c921d33e23c8b2f7c5f1abb235a438
Author: Bob Campbell <bobcampb...@catalyst.net.nz>
Date:   Wed Jul 5 11:15:04 2017 +1200

    samdb/cracknames: do not show recycled when a guid is desired
    
    Previously, when a GUID was desired to
    cracknames, it would include recycled objects as well. This would
    sometimes result in two objects being returned from a query which is
    supposed to return a unique GUID. For example, if a deleted user had
    the same sAMAccountName as a non-deleted user and cracknames was used to
    find the GUID of this account, it would return two GUIDs, and so would
    fail with DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12842
    
    Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Garming Sam <garm...@catalyst.net.nz>

commit 4779afe0d2dd14371b68e80f47d11942456bb365
Author: Bob Campbell <bobcampb...@catalyst.net.nz>
Date:   Wed Jul 5 11:08:45 2017 +1200

    python/tests: add python test for cracknames
    
    This fails due the bug, which causes the related test in
    drsuapi_cracknames.c to flap. It also fails due to us not yet supporting
    DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL or
    DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=12842
    
    Signed-off-by: Bob Campbell <bobcampb...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Garming Sam <garm...@catalyst.net.nz>

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

Summary of changes:
 source4/dsdb/samdb/cracknames.c          |  38 ++++++-
 source4/selftest/tests.py                |   5 +
 source4/torture/drs/python/cracknames.py | 166 +++++++++++++++++++++++++++++++
 3 files changed, 207 insertions(+), 2 deletions(-)
 create mode 100644 source4/torture/drs/python/cracknames.py


Changeset truncated at 500 lines:

diff --git a/source4/dsdb/samdb/cracknames.c b/source4/dsdb/samdb/cracknames.c
index 14d6a53a..d43f510 100644
--- a/source4/dsdb/samdb/cracknames.c
+++ b/source4/dsdb/samdb/cracknames.c
@@ -7,6 +7,7 @@
    Copyright (C) Stefan Metzmacher 2004
    Copyright (C) Andrew Bartlett <abart...@samba.org> 2004-2005
    Copyright (C) Matthieu Patou <m...@matws.net> 2012
+   Copyright (C) Catalyst .Net Ltd 2017
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -880,6 +881,12 @@ static WERROR DsCrackNameOneFilter(struct ldb_context 
*sam_ctx, TALLOC_CTX *mem_
        const char * const _domain_attrs_guid[] = { "ncName", "dnsRoot", NULL};
        const char * const _result_attrs_guid[] = { "objectGUID", NULL};
 
+       const char * const _domain_attrs_upn[] = { "ncName", "dnsRoot", NULL};
+       const char * const _result_attrs_upn[] = { "userPrincipalName", NULL};
+
+       const char * const _domain_attrs_spn[] = { "ncName", "dnsRoot", NULL};
+       const char * const _result_attrs_spn[] = { "servicePrincipalName", 
NULL};
+
        const char * const _domain_attrs_display[] = { "ncName", "dnsRoot", 
NULL};
        const char * const _result_attrs_display[] = { "displayName", 
"samAccountName", NULL};
 
@@ -909,6 +916,14 @@ static WERROR DsCrackNameOneFilter(struct ldb_context 
*sam_ctx, TALLOC_CTX *mem_
                domain_attrs = _domain_attrs_display;
                result_attrs = _result_attrs_display;
                break;
+       case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL:
+               domain_attrs = _domain_attrs_upn;
+               result_attrs = _result_attrs_upn;
+               break;
+       case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL:
+               domain_attrs = _domain_attrs_spn;
+               result_attrs = _result_attrs_spn;
+               break;
        default:
                domain_attrs = _domain_attrs_none;
                result_attrs = _result_attrs_none;
@@ -980,7 +995,7 @@ static WERROR DsCrackNameOneFilter(struct ldb_context 
*sam_ctx, TALLOC_CTX *mem_
                } else {
                        real_search_dn = ldb_get_default_basedn(sam_ctx);
                }
-               if (format_desired == DRSUAPI_DS_NAME_FORMAT_GUID){
+               if (format_offered == DRSUAPI_DS_NAME_FORMAT_GUID){
                         dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED;
                }
                /* search with the 'phantom root' flag */
@@ -1238,7 +1253,17 @@ static WERROR DsCrackNameOneFilter(struct ldb_context 
*sam_ctx, TALLOC_CTX *mem_
                return WERR_OK;
        }
        case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
-               info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+               if (result->elements[0].num_values > 1) {
+                       info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
+                       return WERR_OK;
+               }
+
+               info1->result_name = ldb_msg_find_attr_as_string(result, 
"servicePrincipalName", NULL);
+               if (!info1->result_name) {
+                       info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
+               } else {
+                       info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+               }
                return WERR_OK;
        }
        case DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN: 
@@ -1247,6 +1272,15 @@ static WERROR DsCrackNameOneFilter(struct ldb_context 
*sam_ctx, TALLOC_CTX *mem_
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
        }
+       case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
+               info1->result_name = ldb_msg_find_attr_as_string(result, 
"userPrincipalName", NULL);
+               if (!info1->result_name) {
+                       info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
+               } else {
+                       info1->status = DRSUAPI_DS_NAME_STATUS_OK;
+               }
+               return WERR_OK;
+       }
        default:
                info1->status = DRSUAPI_DS_NAME_STATUS_NO_MAPPING;
                return WERR_OK;
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 15037a2..44c0b08 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -839,6 +839,11 @@ for env in ['ad_dc_ntvfs']:
     planoldpythontestsuite(env, "samba.tests.join",
                            name="samba.tests.join.python(%s)" % env,
                            extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
+    planoldpythontestsuite(env, "cracknames",
+                           extra_path=[os.path.join(samba4srcdir, 
'torture/drs/python')],
+                           name="samba4.drs.cracknames.python(%s)" % env,
+                           environ={'DC1': "$DC_SERVER", 'DC2': '$DC_SERVER'},
+                           extra_args=['-U$DOMAIN/$DC_USERNAME%$DC_PASSWORD'])
 
 planoldpythontestsuite("chgdcpass:local", 
"samba.tests.blackbox.samba_dnsupdate",
                        environ={'DNS_SERVER_IP': '$SERVER_IP'})
diff --git a/source4/torture/drs/python/cracknames.py 
b/source4/torture/drs/python/cracknames.py
new file mode 100644
index 0000000..d8c8ae5
--- /dev/null
+++ b/source4/torture/drs/python/cracknames.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) Catalyst .Net Ltd 2017
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import samba.tests
+import ldb
+import drs_base
+
+from samba.dcerpc import drsuapi
+
+class DrsCracknamesTestCase(drs_base.DrsBaseTestCase):
+    def setUp(self):
+        super(DrsCracknamesTestCase, self).setUp()
+        (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1)
+
+        self.ou = "ou=Cracknames_ou,%s" % self.ldb_dc1.get_default_basedn()
+        self.username = "Cracknames_user"
+        self.user = "cn=%s,%s" % (self.username, self.ou)
+
+        self.ldb_dc1.add({
+            "dn": self.ou,
+            "objectclass": "organizationalUnit"})
+
+        self.user_record = {
+            "dn": self.user,
+            "objectclass": "user",
+            "sAMAccountName" : self.username,
+            "userPrincipalName" : "t...@test.com",
+            "servicePrincipalName" : "test/%s" % 
self.ldb_dc1.get_default_basedn(),
+            "displayName" : "test"}
+
+        self.ldb_dc1.add(self.user_record)
+        self.ldb_dc1.delete(self.user_record["dn"])
+        self.ldb_dc1.add(self.user_record)
+
+        # The formats specified in MS-DRSR 4.1.4.13; DS_NAME_FORMAT
+        # We don't support any of the ones specified in 4.1.4.1.2.
+        self.formats = {
+            drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+            drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
+            drsuapi.DRSUAPI_DS_NAME_FORMAT_DISPLAY,
+            drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
+            drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL,
+            drsuapi.DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
+            drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
+            drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
+            # We currently don't support this
+            #drsuapi.DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
+            # This format is not supported by Windows (or us)
+            #drsuapi.DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN,
+        }
+
+    def tearDown(self):
+        self.ldb_dc1.delete(self.user)
+        self.ldb_dc1.delete(self.ou)
+        super(DrsCracknamesTestCase, self).tearDown()
+
+    def test_Cracknames(self):
+        """
+        Verifies that we can cracknames any of the standard formats
+        (DS_NAME_FORMAT) to a GUID, and that we can cracknames a
+        GUID to any of the standard formats.
+
+        GUID was chosen just so that we don't have to do an n^2 loop.
+        """
+        (result, ctr) = self._do_cracknames(self.user,
+                                            
drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+                                            
drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
+
+        self.assertEquals(ctr.count, 1)
+        self.assertEquals(ctr.array[0].status,
+                          drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
+
+        user_guid = ctr.array[0].result_name
+
+        for name_format in self.formats:
+            (result, ctr) = self._do_cracknames(user_guid,
+                                                
drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
+                                                name_format)
+
+            self.assertEquals(ctr.count, 1)
+            self.assertEquals(ctr.array[0].status,
+                              drsuapi.DRSUAPI_DS_NAME_STATUS_OK,
+                              "Expected 0, got %s, desired format is %s"
+                              % (ctr.array[0].status, name_format))
+
+            (result, ctr) = self._do_cracknames(ctr.array[0].result_name,
+                                                name_format,
+                                                
drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
+
+            self.assertEquals(ctr.count, 1)
+            self.assertEquals(ctr.array[0].status,
+                              drsuapi.DRSUAPI_DS_NAME_STATUS_OK,
+                              "Expected 0, got %s, offered format is %s"
+                              % (ctr.array[0].status, name_format))
+
+    def test_MultiValuedAttribute(self):
+        """
+        Verifies that, if we try and cracknames with the desired output
+        being a multi-valued attribute, it returns
+        DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE.
+        """
+        username = "Cracknames_user_MVA"
+        user = "cn=%s,%s" % (username, self.ou)
+
+        user_record = {
+            "dn": user,
+            "objectclass": "user",
+            "sAMAccountName" : username,
+            "userPrincipalName" : "te...@test.com",
+            "servicePrincipalName" : ["test2/%s" % 
self.ldb_dc1.get_default_basedn(),
+                                      "test3/%s" % 
self.ldb_dc1.get_default_basedn()],
+            "displayName" : "test2"}
+
+        self.ldb_dc1.add(user_record)
+
+        (result, ctr) = self._do_cracknames(user,
+                                            
drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
+                                            
drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
+
+        self.assertEquals(ctr.count, 1)
+        self.assertEquals(ctr.array[0].status,
+                          drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
+
+        user_guid = ctr.array[0].result_name
+
+        (result, ctr) = self._do_cracknames(user_guid,
+                                            
drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
+                                            
drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL)
+
+        self.assertEquals(ctr.count, 1)
+        self.assertEquals(ctr.array[0].status,
+                          drsuapi.DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE)
+
+        self.ldb_dc1.delete(user)
+
+    def _do_cracknames(self, name, format_offered, format_desired):
+        req = drsuapi.DsNameRequest1()
+        names = drsuapi.DsNameString()
+        names.str = name
+
+        req.codepage = 1252 # German, but it doesn't really matter here
+        req.language = 1033
+        req.format_flags = 0
+        req.format_offered = format_offered
+        req.format_desired = format_desired
+        req.count = 1
+        req.names = [names]
+
+        (result, ctr) = self.drs.DsCrackNames(self.drs_handle, 1, req)
+        return (result, ctr)


-- 
Samba Shared Repository

Reply via email to