9bf90f9c9973d67ef9ceee3bcf8b22e2724a8d62
[nivanova/samba-autobuild/.git] / source4 / torture / drs / python / cracknames.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 #
4 # Copyright (C) Catalyst .Net Ltd 2017
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20 import samba.tests
21 import ldb
22 import drs_base
23
24 from samba.dcerpc import drsuapi
25
26 class DrsCracknamesTestCase(drs_base.DrsBaseTestCase):
27     def setUp(self):
28         super(DrsCracknamesTestCase, self).setUp()
29         (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1)
30
31         self.ou = "ou=Cracknames_ou,%s" % self.ldb_dc1.get_default_basedn()
32         self.username = "Cracknames_user"
33         self.user = "cn=%s,%s" % (self.username, self.ou)
34
35         self.ldb_dc1.add({
36             "dn": self.ou,
37             "objectclass": "organizationalUnit"})
38
39         self.user_record = {
40             "dn": self.user,
41             "objectclass": "user",
42             "sAMAccountName" : self.username,
43             "userPrincipalName" : "test@test.com",
44             "servicePrincipalName" : "test/%s" % self.ldb_dc1.get_default_basedn(),
45             "displayName" : "test"}
46
47         self.ldb_dc1.add(self.user_record)
48         self.ldb_dc1.delete(self.user_record["dn"])
49         self.ldb_dc1.add(self.user_record)
50
51         # The formats specified in MS-DRSR 4.1.4.13; DS_NAME_FORMAT
52         # We don't support any of the ones specified in 4.1.4.1.2.
53         self.formats = {
54             drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
55             drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
56             drsuapi.DRSUAPI_DS_NAME_FORMAT_DISPLAY,
57             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
58             drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL,
59             drsuapi.DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
60             drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
61             drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
62             # We currently don't support this
63             #drsuapi.DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
64             # This format is not supported by Windows (or us)
65             #drsuapi.DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN,
66         }
67
68     def tearDown(self):
69         self.ldb_dc1.delete(self.user)
70         self.ldb_dc1.delete(self.ou)
71         super(DrsCracknamesTestCase, self).tearDown()
72
73     def test_Cracknames(self):
74         """
75         Verifies that we can cracknames any of the standard formats
76         (DS_NAME_FORMAT) to a GUID, and that we can cracknames a
77         GUID to any of the standard formats.
78
79         GUID was chosen just so that we don't have to do an n^2 loop.
80         """
81         (result, ctr) = self._do_cracknames(self.user,
82                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
83                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
84
85         self.assertEquals(ctr.count, 1)
86         self.assertEquals(ctr.array[0].status,
87                           drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
88
89         user_guid = ctr.array[0].result_name
90
91         for name_format in self.formats:
92             (result, ctr) = self._do_cracknames(user_guid,
93                                                 drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
94                                                 name_format)
95
96             self.assertEquals(ctr.count, 1)
97             self.assertEquals(ctr.array[0].status,
98                               drsuapi.DRSUAPI_DS_NAME_STATUS_OK,
99                               "Expected 0, got %s, desired format is %s"
100                               % (ctr.array[0].status, name_format))
101
102             (result, ctr) = self._do_cracknames(ctr.array[0].result_name,
103                                                 name_format,
104                                                 drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
105
106             self.assertEquals(ctr.count, 1)
107             self.assertEquals(ctr.array[0].status,
108                               drsuapi.DRSUAPI_DS_NAME_STATUS_OK,
109                               "Expected 0, got %s, offered format is %s"
110                               % (ctr.array[0].status, name_format))
111
112     def test_MultiValuedAttribute(self):
113         """
114         Verifies that, if we try and cracknames with the desired output
115         being a multi-valued attribute, it returns
116         DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE.
117         """
118         username = "Cracknames_user_MVA"
119         user = "cn=%s,%s" % (username, self.ou)
120
121         user_record = {
122             "dn": user,
123             "objectclass": "user",
124             "sAMAccountName" : username,
125             "userPrincipalName" : "test2@test.com",
126             "servicePrincipalName" : ["test2/%s" % self.ldb_dc1.get_default_basedn(),
127                                       "test3/%s" % self.ldb_dc1.get_default_basedn()],
128             "displayName" : "test2"}
129
130         self.ldb_dc1.add(user_record)
131
132         (result, ctr) = self._do_cracknames(user,
133                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
134                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
135
136         self.assertEquals(ctr.count, 1)
137         self.assertEquals(ctr.array[0].status,
138                           drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
139
140         user_guid = ctr.array[0].result_name
141
142         (result, ctr) = self._do_cracknames(user_guid,
143                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
144                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL)
145
146         self.assertEquals(ctr.count, 1)
147         self.assertEquals(ctr.array[0].status,
148                           drsuapi.DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE)
149
150         self.ldb_dc1.delete(user)
151
152     def test_NoSPNAttribute(self):
153         """
154         Verifies that, if we try and cracknames with the desired output
155         being an SPN, it returns
156         DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE.
157         """
158         username = "Cracknames_no_SPN"
159         user = "cn=%s,%s" % (username, self.ou)
160
161         user_record = {
162             "dn": user,
163             "objectclass": "user",
164             "sAMAccountName" : username,
165             "userPrincipalName" : "test4@test.com",
166             "displayName" : "test4"}
167
168         self.ldb_dc1.add(user_record)
169
170         (result, ctr) = self._do_cracknames(user,
171                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
172                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
173
174         self.assertEquals(ctr.count, 1)
175         self.assertEquals(ctr.array[0].status,
176                           drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
177
178         user_guid = ctr.array[0].result_name
179
180         (result, ctr) = self._do_cracknames(user_guid,
181                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
182                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL)
183
184         self.assertEquals(ctr.count, 1)
185         self.assertEquals(ctr.array[0].status,
186                           drsuapi.DRSUAPI_DS_NAME_STATUS_NOT_FOUND)
187
188         self.ldb_dc1.delete(user)
189
190     def _do_cracknames(self, name, format_offered, format_desired):
191         req = drsuapi.DsNameRequest1()
192         names = drsuapi.DsNameString()
193         names.str = name
194
195         req.codepage = 1252 # German, but it doesn't really matter here
196         req.language = 1033
197         req.format_flags = 0
198         req.format_offered = format_offered
199         req.format_desired = format_desired
200         req.count = 1
201         req.names = [names]
202
203         (result, ctr) = self.drs.DsCrackNames(self.drs_handle, 1, req)
204         return (result, ctr)