PY3: change shebang to python3 in source4/torture dir
[samba.git] / source4 / torture / drs / python / cracknames.py
1 #!/usr/bin/env python3
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
27 class DrsCracknamesTestCase(drs_base.DrsBaseTestCase):
28     def setUp(self):
29         super(DrsCracknamesTestCase, self).setUp()
30         (self.drs, self.drs_handle) = self._ds_bind(self.dnsname_dc1)
31
32         self.ou = "ou=Cracknames_ou,%s" % self.ldb_dc1.get_default_basedn()
33         self.username = "Cracknames_user"
34         self.user = "cn=%s,%s" % (self.username, self.ou)
35
36         self.ldb_dc1.add({
37             "dn": self.ou,
38             "objectclass": "organizationalUnit"})
39
40         self.user_record = {
41             "dn": self.user,
42             "objectclass": "user",
43             "sAMAccountName": self.username,
44             "userPrincipalName": "test@test.com",
45             "servicePrincipalName": "test/%s" % self.ldb_dc1.get_default_basedn(),
46             "displayName": "test"}
47
48         self.ldb_dc1.add(self.user_record)
49         self.ldb_dc1.delete(self.user_record["dn"])
50         self.ldb_dc1.add(self.user_record)
51
52         # The formats specified in MS-DRSR 4.1.4.13; DS_NAME_FORMAT
53         # We don't support any of the ones specified in 4.1.4.1.2.
54         self.formats = {
55             drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
56             drsuapi.DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT,
57             drsuapi.DRSUAPI_DS_NAME_FORMAT_DISPLAY,
58             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
59             drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL,
60             drsuapi.DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
61             drsuapi.DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX,
62             drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
63             # We currently don't support this
64             # drsuapi.DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
65             # This format is not supported by Windows (or us)
66             # drsuapi.DRSUAPI_DS_NAME_FORMAT_DNS_DOMAIN,
67         }
68
69     def tearDown(self):
70         self.ldb_dc1.delete(self.user)
71         self.ldb_dc1.delete(self.ou)
72         super(DrsCracknamesTestCase, self).tearDown()
73
74     def test_Cracknames(self):
75         """
76         Verifies that we can cracknames any of the standard formats
77         (DS_NAME_FORMAT) to a GUID, and that we can cracknames a
78         GUID to any of the standard formats.
79
80         GUID was chosen just so that we don't have to do an n^2 loop.
81         """
82         (result, ctr) = self._do_cracknames(self.user,
83                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
84                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
85
86         self.assertEquals(ctr.count, 1)
87         self.assertEquals(ctr.array[0].status,
88                           drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
89
90         user_guid = ctr.array[0].result_name
91
92         for name_format in self.formats:
93             (result, ctr) = self._do_cracknames(user_guid,
94                                                 drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
95                                                 name_format)
96
97             self.assertEquals(ctr.count, 1)
98             self.assertEquals(ctr.array[0].status,
99                               drsuapi.DRSUAPI_DS_NAME_STATUS_OK,
100                               "Expected 0, got %s, desired format is %s"
101                               % (ctr.array[0].status, name_format))
102
103             (result, ctr) = self._do_cracknames(ctr.array[0].result_name,
104                                                 name_format,
105                                                 drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
106
107             self.assertEquals(ctr.count, 1)
108             self.assertEquals(ctr.array[0].status,
109                               drsuapi.DRSUAPI_DS_NAME_STATUS_OK,
110                               "Expected 0, got %s, offered format is %s"
111                               % (ctr.array[0].status, name_format))
112
113     def test_MultiValuedAttribute(self):
114         """
115         Verifies that, if we try and cracknames with the desired output
116         being a multi-valued attribute, it returns
117         DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE.
118         """
119         username = "Cracknames_user_MVA"
120         user = "cn=%s,%s" % (username, self.ou)
121
122         user_record = {
123             "dn": user,
124             "objectclass": "user",
125             "sAMAccountName": username,
126             "userPrincipalName": "test2@test.com",
127             "servicePrincipalName": ["test2/%s" % self.ldb_dc1.get_default_basedn(),
128                                      "test3/%s" % self.ldb_dc1.get_default_basedn()],
129             "displayName": "test2"}
130
131         self.ldb_dc1.add(user_record)
132
133         (result, ctr) = self._do_cracknames(user,
134                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
135                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
136
137         self.assertEquals(ctr.count, 1)
138         self.assertEquals(ctr.array[0].status,
139                           drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
140
141         user_guid = ctr.array[0].result_name
142
143         (result, ctr) = self._do_cracknames(user_guid,
144                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
145                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL)
146
147         self.assertEquals(ctr.count, 1)
148         self.assertEquals(ctr.array[0].status,
149                           drsuapi.DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE)
150
151         self.ldb_dc1.delete(user)
152
153     def test_NoSPNAttribute(self):
154         """
155         Verifies that, if we try and cracknames with the desired output
156         being an SPN, it returns
157         DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE.
158         """
159         username = "Cracknames_no_SPN"
160         user = "cn=%s,%s" % (username, self.ou)
161
162         user_record = {
163             "dn": user,
164             "objectclass": "user",
165             "sAMAccountName" : username,
166             "userPrincipalName" : "test4@test.com",
167             "displayName" : "test4"}
168
169         self.ldb_dc1.add(user_record)
170
171         (result, ctr) = self._do_cracknames(user,
172                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_FQDN_1779,
173                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID)
174
175         self.assertEquals(ctr.count, 1)
176         self.assertEquals(ctr.array[0].status,
177                           drsuapi.DRSUAPI_DS_NAME_STATUS_OK)
178
179         user_guid = ctr.array[0].result_name
180
181         (result, ctr) = self._do_cracknames(user_guid,
182                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_GUID,
183                                             drsuapi.DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL)
184
185         self.assertEquals(ctr.count, 1)
186         self.assertEquals(ctr.array[0].status,
187                           drsuapi.DRSUAPI_DS_NAME_STATUS_NOT_FOUND)
188
189         self.ldb_dc1.delete(user)
190
191     def _do_cracknames(self, name, format_offered, format_desired):
192         req = drsuapi.DsNameRequest1()
193         names = drsuapi.DsNameString()
194         names.str = name
195
196         req.codepage = 1252  # German, but it doesn't really matter here
197         req.language = 1033
198         req.format_flags = 0
199         req.format_offered = format_offered
200         req.format_desired = format_desired
201         req.count = 1
202         req.names = [names]
203
204         (result, ctr) = self.drs.DsCrackNames(self.drs_handle, 1, req)
205         return (result, ctr)