PEP8: fix E303: too many blank lines (2)
[nivanova/samba-autobuild/.git] / source4 / dsdb / tests / python / sam.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # This is a port of the original in testprogs/ejs/ldap.js
4
5 from __future__ import print_function
6 import optparse
7 import sys
8 import os
9 import time
10
11 sys.path.insert(0, "bin/python")
12 import samba
13 from samba.tests.subunitrun import SubunitOptions, TestProgram
14
15 import samba.getopt as options
16
17 from samba.credentials import Credentials, DONT_USE_KERBEROS
18 from samba.auth import system_session
19 from ldb import SCOPE_BASE, LdbError
20 from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
21 from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
22 from ldb import ERR_OTHER, ERR_NO_SUCH_ATTRIBUTE
23 from ldb import ERR_OBJECT_CLASS_VIOLATION
24 from ldb import ERR_CONSTRAINT_VIOLATION
25 from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
26 from ldb import ERR_INSUFFICIENT_ACCESS_RIGHTS
27 from ldb import ERR_INVALID_CREDENTIALS
28 from ldb import ERR_STRONG_AUTH_REQUIRED
29 from ldb import Message, MessageElement, Dn
30 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
31 from samba.samdb import SamDB
32 from samba.dsdb import (UF_NORMAL_ACCOUNT, UF_ACCOUNTDISABLE,
33                         UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT,
34                         UF_PARTIAL_SECRETS_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT,
35                         UF_INTERDOMAIN_TRUST_ACCOUNT, UF_SMARTCARD_REQUIRED,
36                         UF_PASSWD_NOTREQD, UF_LOCKOUT, UF_PASSWORD_EXPIRED, ATYPE_NORMAL_ACCOUNT,
37                         GTYPE_SECURITY_BUILTIN_LOCAL_GROUP, GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
38                         GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP,
39                         GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP, GTYPE_DISTRIBUTION_GLOBAL_GROUP,
40                         GTYPE_DISTRIBUTION_UNIVERSAL_GROUP,
41                         ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_UNIVERSAL_GROUP,
42                         ATYPE_SECURITY_LOCAL_GROUP, ATYPE_DISTRIBUTION_GLOBAL_GROUP,
43                         ATYPE_DISTRIBUTION_UNIVERSAL_GROUP, ATYPE_DISTRIBUTION_LOCAL_GROUP,
44                         ATYPE_WORKSTATION_TRUST)
45 from samba.dcerpc.security import (DOMAIN_RID_USERS, DOMAIN_RID_ADMINS,
46                                    DOMAIN_RID_DOMAIN_MEMBERS, DOMAIN_RID_DCS, DOMAIN_RID_READONLY_DCS)
47
48 from samba.ndr import ndr_unpack
49 from samba.dcerpc import drsblobs
50 from samba.dcerpc import drsuapi
51 from samba.dcerpc import security
52 from samba.tests import delete_force
53 from samba import gensec
54 from samba import werror
55
56 parser = optparse.OptionParser("sam.py [options] <host>")
57 sambaopts = options.SambaOptions(parser)
58 parser.add_option_group(sambaopts)
59 parser.add_option_group(options.VersionOptions(parser))
60 # use command line creds if available
61 credopts = options.CredentialsOptions(parser)
62 parser.add_option_group(credopts)
63 subunitopts = SubunitOptions(parser)
64 parser.add_option_group(subunitopts)
65 opts, args = parser.parse_args()
66
67 if len(args) < 1:
68     parser.print_usage()
69     sys.exit(1)
70
71 host = args[0]
72
73 lp = sambaopts.get_loadparm()
74 creds = credopts.get_credentials(lp)
75 creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
76
77
78 class SamTests(samba.tests.TestCase):
79
80     def setUp(self):
81         super(SamTests, self).setUp()
82         self.ldb = ldb
83         self.base_dn = ldb.domain_dn()
84
85         print("baseDN: %s\n" % self.base_dn)
86
87         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
88         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
89         delete_force(self.ldb, "cn=ldaptest\,specialuser,cn=users," + self.base_dn)
90         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
91         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
92         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
93
94     def test_users_groups(self):
95         """This tests the SAM users and groups behaviour"""
96         print("Testing users and groups behaviour\n")
97
98         ldb.add({
99             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
100             "objectclass": "group"})
101
102         ldb.add({
103             "dn": "cn=ldaptestgroup2,cn=users," + self.base_dn,
104             "objectclass": "group"})
105
106         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
107                           scope=SCOPE_BASE, attrs=["objectSID"])
108         self.assertTrue(len(res1) == 1)
109         group_rid_1 = security.dom_sid(ldb.schema_format_value("objectSID",
110                                                                res1[0]["objectSID"][0])).split()[1]
111
112         res1 = ldb.search("cn=ldaptestgroup2,cn=users," + self.base_dn,
113                           scope=SCOPE_BASE, attrs=["objectSID"])
114         self.assertTrue(len(res1) == 1)
115         group_rid_2 = security.dom_sid(ldb.schema_format_value("objectSID",
116                                                                res1[0]["objectSID"][0])).split()[1]
117
118         # Try to create a user with an invalid account name
119         try:
120             ldb.add({
121                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
122                 "objectclass": "user",
123                 "sAMAccountName": "administrator"})
124             self.fail()
125         except LdbError as e9:
126             (num, _) = e9.args
127             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
128         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
129
130         # Try to create a user with an invalid account name
131         try:
132             ldb.add({
133                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
134                 "objectclass": "user",
135                 "sAMAccountName": []})
136             self.fail()
137         except LdbError as e10:
138             (num, _) = e10.args
139             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
140         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
141
142         # Try to create a user with an invalid primary group
143         try:
144             ldb.add({
145                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
146                 "objectclass": "user",
147                 "primaryGroupID": "0"})
148             self.fail()
149         except LdbError as e11:
150             (num, _) = e11.args
151             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
152         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
153
154         # Try to Create a user with a valid primary group
155         try:
156             ldb.add({
157                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
158                 "objectclass": "user",
159                 "primaryGroupID": str(group_rid_1)})
160             self.fail()
161         except LdbError as e12:
162             (num, _) = e12.args
163             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
164         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
165
166         # Test to see how we should behave when the user account doesn't
167         # exist
168         m = Message()
169         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
170         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
171                                              "primaryGroupID")
172         try:
173             ldb.modify(m)
174             self.fail()
175         except LdbError as e13:
176             (num, _) = e13.args
177             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
178
179         # Test to see how we should behave when the account isn't a user
180         m = Message()
181         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
182         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
183                                              "primaryGroupID")
184         try:
185             ldb.modify(m)
186             self.fail()
187         except LdbError as e14:
188             (num, _) = e14.args
189             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
190
191         # Test default primary groups on add operations
192
193         ldb.add({
194             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
195             "objectclass": "user"})
196
197         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
198                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
199         self.assertTrue(len(res1) == 1)
200         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
201
202         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
203
204         ldb.add({
205             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
206             "objectclass": "user",
207             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
208
209         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
210                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
211         self.assertTrue(len(res1) == 1)
212         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
213
214         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
215
216         # unfortunately the INTERDOMAIN_TRUST_ACCOUNT case cannot be tested
217         # since such accounts aren't directly creatable (ACCESS_DENIED)
218
219         ldb.add({
220             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
221             "objectclass": "computer",
222             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD)})
223
224         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
225                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
226         self.assertTrue(len(res1) == 1)
227         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DOMAIN_MEMBERS))
228
229         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
230
231         ldb.add({
232             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
233             "objectclass": "computer",
234             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT | UF_PASSWD_NOTREQD)})
235
236         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
237                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
238         self.assertTrue(len(res1) == 1)
239         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DCS))
240
241         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
242
243         # Read-only DC accounts are only creatable by
244         # UF_WORKSTATION_TRUST_ACCOUNT and work only on DCs >= 2008 (therefore
245         # we have a fallback in the assertion)
246         ldb.add({
247             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
248             "objectclass": "computer",
249             "userAccountControl": str(UF_PARTIAL_SECRETS_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD)})
250
251         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
252                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
253         self.assertTrue(len(res1) == 1)
254         self.assertTrue(res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_READONLY_DCS) or
255                         res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_DOMAIN_MEMBERS))
256
257         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
258
259         # Test default primary groups on modify operations
260
261         ldb.add({
262             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
263             "objectclass": "user"})
264
265         m = Message()
266         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
267         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
268                                                  "userAccountControl")
269         ldb.modify(m)
270
271         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
272                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
273         self.assertTrue(len(res1) == 1)
274         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
275
276         # unfortunately the INTERDOMAIN_TRUST_ACCOUNT case cannot be tested
277         # since such accounts aren't directly creatable (ACCESS_DENIED)
278
279         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
280
281         ldb.add({
282             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
283             "objectclass": "computer"})
284
285         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
286                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
287         self.assertTrue(len(res1) == 1)
288         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
289
290         m = Message()
291         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
292         m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
293                                                  "userAccountControl")
294         ldb.modify(m)
295
296         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
297                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
298         self.assertTrue(len(res1) == 1)
299         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DOMAIN_MEMBERS))
300
301         m = Message()
302         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
303         m["userAccountControl"] = MessageElement(str(UF_SERVER_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
304                                                  "userAccountControl")
305         ldb.modify(m)
306
307         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
308                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
309         self.assertTrue(len(res1) == 1)
310         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DCS))
311
312         # Read-only DC accounts are only creatable by
313         # UF_WORKSTATION_TRUST_ACCOUNT and work only on DCs >= 2008 (therefore
314         # we have a fallback in the assertion)
315         m = Message()
316         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
317         m["userAccountControl"] = MessageElement(str(UF_PARTIAL_SECRETS_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
318                                                  "userAccountControl")
319         ldb.modify(m)
320
321         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
322                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
323         self.assertTrue(len(res1) == 1)
324         self.assertTrue(res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_READONLY_DCS) or
325                         res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_DOMAIN_MEMBERS))
326
327         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
328
329         # Recreate account for further tests
330
331         ldb.add({
332             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
333             "objectclass": "user"})
334
335         # Try to set an invalid account name
336         m = Message()
337         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
338         m["sAMAccountName"] = MessageElement("administrator", FLAG_MOD_REPLACE,
339                                              "sAMAccountName")
340         try:
341             ldb.modify(m)
342             self.fail()
343         except LdbError as e15:
344             (num, _) = e15.args
345             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
346
347         # But to reset the actual "sAMAccountName" should still be possible
348         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
349                           scope=SCOPE_BASE, attrs=["sAMAccountName"])
350         self.assertTrue(len(res1) == 1)
351         m = Message()
352         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
353         m["sAMAccountName"] = MessageElement(res1[0]["sAMAccountName"][0], FLAG_MOD_REPLACE,
354                                              "sAMAccountName")
355         ldb.modify(m)
356
357         # And another (free) name should be possible as well
358         m = Message()
359         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
360         m["sAMAccountName"] = MessageElement("xxx_ldaptestuser_xxx", FLAG_MOD_REPLACE,
361                                              "sAMAccountName")
362         ldb.modify(m)
363
364         # We should be able to reset our actual primary group
365         m = Message()
366         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
367         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_USERS), FLAG_MOD_REPLACE,
368                                              "primaryGroupID")
369         ldb.modify(m)
370
371         # Try to add invalid primary group
372         m = Message()
373         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
374         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
375                                              "primaryGroupID")
376         try:
377             ldb.modify(m)
378             self.fail()
379         except LdbError as e16:
380             (num, _) = e16.args
381             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
382
383         # Try to make group 1 primary - should be denied since it is not yet
384         # secondary
385         m = Message()
386         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
387         m["primaryGroupID"] = MessageElement(str(group_rid_1),
388                                              FLAG_MOD_REPLACE, "primaryGroupID")
389         try:
390             ldb.modify(m)
391             self.fail()
392         except LdbError as e17:
393             (num, _) = e17.args
394             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
395
396         # Make group 1 secondary
397         m = Message()
398         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
399         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
400                                      FLAG_MOD_REPLACE, "member")
401         ldb.modify(m)
402
403         # Make group 1 primary
404         m = Message()
405         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
406         m["primaryGroupID"] = MessageElement(str(group_rid_1),
407                                              FLAG_MOD_REPLACE, "primaryGroupID")
408         ldb.modify(m)
409
410         # Try to delete group 1 - should be denied
411         try:
412             ldb.delete("cn=ldaptestgroup,cn=users," + self.base_dn)
413             self.fail()
414         except LdbError as e18:
415             (num, _) = e18.args
416             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
417
418         # Try to add group 1 also as secondary - should be denied
419         m = Message()
420         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
421         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
422                                      FLAG_MOD_ADD, "member")
423         try:
424             ldb.modify(m)
425             self.fail()
426         except LdbError as e19:
427             (num, _) = e19.args
428             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
429
430         # Try to add invalid member to group 1 - should be denied
431         m = Message()
432         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
433         m["member"] = MessageElement(
434             "cn=ldaptestuser3,cn=users," + self.base_dn,
435             FLAG_MOD_ADD, "member")
436         try:
437             ldb.modify(m)
438             self.fail()
439         except LdbError as e20:
440             (num, _) = e20.args
441             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
442
443         # Make group 2 secondary
444         m = Message()
445         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
446         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
447                                      FLAG_MOD_ADD, "member")
448         ldb.modify(m)
449
450         # Swap the groups
451         m = Message()
452         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
453         m["primaryGroupID"] = MessageElement(str(group_rid_2),
454                                              FLAG_MOD_REPLACE, "primaryGroupID")
455         ldb.modify(m)
456
457         # Swap the groups (does not really make sense but does the same)
458         m = Message()
459         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
460         m["primaryGroupID"] = MessageElement(str(group_rid_1),
461                                              FLAG_MOD_REPLACE, "primaryGroupID")
462         m["primaryGroupID"] = MessageElement(str(group_rid_2),
463                                              FLAG_MOD_REPLACE, "primaryGroupID")
464         ldb.modify(m)
465
466         # Old primary group should contain a "member" attribute for the user,
467         # the new shouldn't contain anymore one
468         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
469                           scope=SCOPE_BASE, attrs=["member"])
470         self.assertTrue(len(res1) == 1)
471         self.assertTrue(len(res1[0]["member"]) == 1)
472         self.assertEquals(res1[0]["member"][0].lower(),
473                           ("cn=ldaptestuser,cn=users," + self.base_dn).lower())
474
475         res1 = ldb.search("cn=ldaptestgroup2, cn=users," + self.base_dn,
476                           scope=SCOPE_BASE, attrs=["member"])
477         self.assertTrue(len(res1) == 1)
478         self.assertFalse("member" in res1[0])
479
480         # Primary group member
481         m = Message()
482         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
483         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
484                                      FLAG_MOD_DELETE, "member")
485         try:
486             ldb.modify(m)
487             self.fail()
488         except LdbError as e21:
489             (num, _) = e21.args
490             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
491
492         # Delete invalid group member
493         m = Message()
494         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
495         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
496                                      FLAG_MOD_DELETE, "member")
497         try:
498             ldb.modify(m)
499             self.fail()
500         except LdbError as e22:
501             (num, _) = e22.args
502             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
503
504         # Also this should be denied
505         try:
506             ldb.add({
507                 "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
508                 "objectclass": "user",
509                 "primaryGroupID": "0"})
510             self.fail()
511         except LdbError as e23:
512             (num, _) = e23.args
513             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
514
515         # Recreate user accounts
516
517         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
518
519         ldb.add({
520             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
521             "objectclass": "user"})
522
523         ldb.add({
524             "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
525             "objectclass": "user"})
526
527         m = Message()
528         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
529         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
530                                      FLAG_MOD_ADD, "member")
531         ldb.modify(m)
532
533         # Already added
534         m = Message()
535         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
536         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
537                                      FLAG_MOD_ADD, "member")
538         try:
539             ldb.modify(m)
540             self.fail()
541         except LdbError as e24:
542             (num, _) = e24.args
543             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
544
545         # Already added, but as <SID=...>
546         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
547                           scope=SCOPE_BASE, attrs=["objectSid"])
548         self.assertTrue(len(res1) == 1)
549         sid_bin = res1[0]["objectSid"][0]
550         sid_str = ("<SID=" + ldb.schema_format_value("objectSid", sid_bin) + ">").upper()
551
552         m = Message()
553         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
554         m["member"] = MessageElement(sid_str, FLAG_MOD_ADD, "member")
555         try:
556             ldb.modify(m)
557             self.fail()
558         except LdbError as e25:
559             (num, _) = e25.args
560             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
561
562         # Invalid member
563         m = Message()
564         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
565         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
566                                      FLAG_MOD_REPLACE, "member")
567         try:
568             ldb.modify(m)
569             self.fail()
570         except LdbError as e26:
571             (num, _) = e26.args
572             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
573
574         # Invalid member
575         m = Message()
576         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
577         m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn,
578                                       "cn=ldaptestuser1,cn=users," + self.base_dn],
579                                      FLAG_MOD_REPLACE, "member")
580         try:
581             ldb.modify(m)
582             self.fail()
583         except LdbError as e27:
584             (num, _) = e27.args
585             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
586
587         # Invalid member
588         m = Message()
589         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
590         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
591                                      FLAG_MOD_REPLACE, "member")
592         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
593                                      FLAG_MOD_ADD, "member")
594         try:
595             ldb.modify(m)
596             self.fail()
597         except LdbError as e28:
598             (num, _) = e28.args
599             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
600
601         m = Message()
602         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
603         m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn,
604                                       "cn=ldaptestuser2,cn=users," + self.base_dn],
605                                      FLAG_MOD_REPLACE, "member")
606         ldb.modify(m)
607
608         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
609         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
610         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
611         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
612
613         # Make also a small test for accounts with special DNs ("," in this case)
614         ldb.add({
615             "dn": "cn=ldaptest\,specialuser,cn=users," + self.base_dn,
616             "objectclass": "user"})
617         delete_force(self.ldb, "cn=ldaptest\,specialuser,cn=users," + self.base_dn)
618
619     def test_sam_attributes(self):
620         """Test the behaviour of special attributes of SAM objects"""
621         print("Testing the behaviour of special attributes of SAM objects\n")
622
623         ldb.add({
624             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
625             "objectclass": "user"})
626         ldb.add({
627             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
628             "objectclass": "group"})
629
630         m = Message()
631         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
632         m["groupType"] = MessageElement(str(GTYPE_SECURITY_GLOBAL_GROUP), FLAG_MOD_ADD,
633                                         "groupType")
634         try:
635             ldb.modify(m)
636             self.fail()
637         except LdbError as e29:
638             (num, _) = e29.args
639             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
640
641         # Delete protection tests
642
643         for attr in ["nTSecurityDescriptor", "objectSid", "sAMAccountType",
644                      "sAMAccountName", "groupType"]:
645
646             m = Message()
647             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
648             m[attr] = MessageElement([], FLAG_MOD_REPLACE, attr)
649             try:
650                 ldb.modify(m)
651                 self.fail()
652             except LdbError as e:
653                 (num, _) = e.args
654                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
655
656             m = Message()
657             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
658             m[attr] = MessageElement([], FLAG_MOD_DELETE, attr)
659             try:
660                 ldb.modify(m)
661                 self.fail()
662             except LdbError as e1:
663                 (num, _) = e1.args
664                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
665
666         m = Message()
667         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
668         m["primaryGroupID"] = MessageElement("513", FLAG_MOD_ADD,
669                                              "primaryGroupID")
670         try:
671             ldb.modify(m)
672             self.fail()
673         except LdbError as e30:
674             (num, _) = e30.args
675             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
676
677         m = Message()
678         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
679         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_ADD,
680                                                  "userAccountControl")
681         try:
682             ldb.modify(m)
683             self.fail()
684         except LdbError as e31:
685             (num, _) = e31.args
686             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
687
688         m = Message()
689         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
690         m["objectSid"] = MessageElement("xxxxxxxxxxxxxxxx", FLAG_MOD_ADD,
691                                         "objectSid")
692         try:
693             ldb.modify(m)
694             self.fail()
695         except LdbError as e32:
696             (num, _) = e32.args
697             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
698
699         m = Message()
700         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
701         m["sAMAccountType"] = MessageElement("0", FLAG_MOD_ADD,
702                                              "sAMAccountType")
703         try:
704             ldb.modify(m)
705             self.fail()
706         except LdbError as e33:
707             (num, _) = e33.args
708             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
709
710         m = Message()
711         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
712         m["sAMAccountName"] = MessageElement("test", FLAG_MOD_ADD,
713                                              "sAMAccountName")
714         try:
715             ldb.modify(m)
716             self.fail()
717         except LdbError as e34:
718             (num, _) = e34.args
719             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
720
721         # Delete protection tests
722
723         for attr in ["nTSecurityDescriptor", "objectSid", "sAMAccountType",
724                      "sAMAccountName", "primaryGroupID", "userAccountControl",
725                      "accountExpires", "badPasswordTime", "badPwdCount",
726                      "codePage", "countryCode", "lastLogoff", "lastLogon",
727                      "logonCount", "pwdLastSet"]:
728
729             m = Message()
730             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
731             m[attr] = MessageElement([], FLAG_MOD_REPLACE, attr)
732             try:
733                 ldb.modify(m)
734                 self.fail()
735             except LdbError as e2:
736                 (num, _) = e2.args
737                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
738
739             m = Message()
740             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
741             m[attr] = MessageElement([], FLAG_MOD_DELETE, attr)
742             try:
743                 ldb.modify(m)
744                 self.fail()
745             except LdbError as e3:
746                 (num, _) = e3.args
747                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
748
749         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
750         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
751
752     def test_primary_group_token_constructed(self):
753         """Test the primary group token behaviour (hidden-generated-readonly attribute on groups) and some other constructed attributes"""
754         print("Testing primary group token behaviour and other constructed attributes\n")
755
756         try:
757             ldb.add({
758                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
759                 "objectclass": "group",
760                 "primaryGroupToken": "100"})
761             self.fail()
762         except LdbError as e35:
763             (num, _) = e35.args
764             self.assertEquals(num, ERR_UNDEFINED_ATTRIBUTE_TYPE)
765         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
766
767         ldb.add({
768             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
769             "objectclass": "user"})
770
771         ldb.add({
772             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
773             "objectclass": "group"})
774
775         # Testing for one invalid, and one valid operational attribute, but also the things they are built from
776         res1 = ldb.search(self.base_dn,
777                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName", "objectClass", "objectSid"])
778         self.assertTrue(len(res1) == 1)
779         self.assertFalse("primaryGroupToken" in res1[0])
780         self.assertTrue("canonicalName" in res1[0])
781         self.assertTrue("objectClass" in res1[0])
782         self.assertTrue("objectSid" in res1[0])
783
784         res1 = ldb.search(self.base_dn,
785                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName"])
786         self.assertTrue(len(res1) == 1)
787         self.assertFalse("primaryGroupToken" in res1[0])
788         self.assertFalse("objectSid" in res1[0])
789         self.assertFalse("objectClass" in res1[0])
790         self.assertTrue("canonicalName" in res1[0])
791
792         res1 = ldb.search("cn=users," + self.base_dn,
793                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
794         self.assertTrue(len(res1) == 1)
795         self.assertFalse("primaryGroupToken" in res1[0])
796
797         res1 = ldb.search("cn=ldaptestuser, cn=users," + self.base_dn,
798                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
799         self.assertTrue(len(res1) == 1)
800         self.assertFalse("primaryGroupToken" in res1[0])
801
802         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
803                           scope=SCOPE_BASE)
804         self.assertTrue(len(res1) == 1)
805         self.assertFalse("primaryGroupToken" in res1[0])
806
807         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
808                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "objectSID"])
809         self.assertTrue(len(res1) == 1)
810         primary_group_token = int(res1[0]["primaryGroupToken"][0])
811
812         rid = security.dom_sid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0])).split()[1]
813         self.assertEquals(primary_group_token, rid)
814
815         m = Message()
816         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
817         m["primaryGroupToken"] = "100"
818         try:
819             ldb.modify(m)
820             self.fail()
821         except LdbError as e36:
822             (num, _) = e36.args
823             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
824
825         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
826         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
827
828     def test_tokenGroups(self):
829         """Test the tokenGroups behaviour (hidden-generated-readonly attribute on SAM objects)"""
830         print("Testing tokenGroups behaviour\n")
831
832         # The domain object shouldn't contain any "tokenGroups" entry
833         res = ldb.search(self.base_dn, scope=SCOPE_BASE, attrs=["tokenGroups"])
834         self.assertTrue(len(res) == 1)
835         self.assertFalse("tokenGroups" in res[0])
836
837         # The domain administrator should contain "tokenGroups" entries
838         # (the exact number depends on the domain/forest function level and the
839         # DC software versions)
840         res = ldb.search("cn=Administrator,cn=Users," + self.base_dn,
841                          scope=SCOPE_BASE, attrs=["tokenGroups"])
842         self.assertTrue(len(res) == 1)
843         self.assertTrue("tokenGroups" in res[0])
844
845         ldb.add({
846             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
847             "objectclass": "user"})
848
849         # This testuser should contain at least two "tokenGroups" entries
850         # (exactly two on an unmodified "Domain Users" and "Users" group)
851         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
852                          scope=SCOPE_BASE, attrs=["tokenGroups"])
853         self.assertTrue(len(res) == 1)
854         self.assertTrue(len(res[0]["tokenGroups"]) >= 2)
855
856         # one entry which we need to find should point to domains "Domain Users"
857         # group and another entry should point to the builtin "Users"group
858         domain_users_group_found = False
859         users_group_found = False
860         for sid in res[0]["tokenGroups"]:
861             rid = security.dom_sid(ldb.schema_format_value("objectSID", sid)).split()[1]
862             if rid == 513:
863                 domain_users_group_found = True
864             if rid == 545:
865                 users_group_found = True
866
867         self.assertTrue(domain_users_group_found)
868         self.assertTrue(users_group_found)
869
870         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
871
872     def test_groupType(self):
873         """Test the groupType behaviour"""
874         print("Testing groupType behaviour\n")
875
876         # You can never create or change to a
877         # "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP"
878
879         # Add operation
880
881         # Invalid attribute
882         try:
883             ldb.add({
884                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
885                 "objectclass": "group",
886                 "groupType": "0"})
887             self.fail()
888         except LdbError as e37:
889             (num, _) = e37.args
890             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
891         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
892
893         try:
894             ldb.add({
895                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
896                 "objectclass": "group",
897                 "groupType": str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP)})
898             self.fail()
899         except LdbError as e38:
900             (num, _) = e38.args
901             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
902         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
903
904         ldb.add({
905             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
906             "objectclass": "group",
907             "groupType": str(GTYPE_SECURITY_GLOBAL_GROUP)})
908
909         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
910                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
911         self.assertTrue(len(res1) == 1)
912         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
913                           ATYPE_SECURITY_GLOBAL_GROUP)
914         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
915
916         ldb.add({
917             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
918             "objectclass": "group",
919             "groupType": str(GTYPE_SECURITY_UNIVERSAL_GROUP)})
920
921         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
922                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
923         self.assertTrue(len(res1) == 1)
924         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
925                           ATYPE_SECURITY_UNIVERSAL_GROUP)
926         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
927
928         ldb.add({
929             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
930             "objectclass": "group",
931             "groupType": str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)})
932
933         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
934                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
935         self.assertTrue(len(res1) == 1)
936         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
937                           ATYPE_SECURITY_LOCAL_GROUP)
938         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
939
940         ldb.add({
941             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
942             "objectclass": "group",
943             "groupType": str(GTYPE_DISTRIBUTION_GLOBAL_GROUP)})
944
945         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
946                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
947         self.assertTrue(len(res1) == 1)
948         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
949                           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
950         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
951
952         ldb.add({
953             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
954             "objectclass": "group",
955             "groupType": str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP)})
956
957         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
958                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
959         self.assertTrue(len(res1) == 1)
960         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
961                           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
962         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
963
964         ldb.add({
965             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
966             "objectclass": "group",
967             "groupType": str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)})
968
969         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
970                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
971         self.assertTrue(len(res1) == 1)
972         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
973                           ATYPE_DISTRIBUTION_LOCAL_GROUP)
974         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
975
976         # Modify operation
977
978         ldb.add({
979             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
980             "objectclass": "group"})
981
982         # We can change in this direction: global <-> universal <-> local
983         # On each step also the group type itself (security/distribution) is
984         # variable.
985
986         # After creation we should have a "security global group"
987         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
988                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
989         self.assertTrue(len(res1) == 1)
990         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
991                           ATYPE_SECURITY_GLOBAL_GROUP)
992
993         # Invalid attribute
994         try:
995             m = Message()
996             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
997             m["groupType"] = MessageElement("0",
998                                             FLAG_MOD_REPLACE, "groupType")
999             ldb.modify(m)
1000             self.fail()
1001         except LdbError as e39:
1002             (num, _) = e39.args
1003             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1004
1005         # Security groups
1006
1007         # Default is "global group"
1008
1009         m = Message()
1010         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1011         m["groupType"] = MessageElement(
1012             str(GTYPE_SECURITY_GLOBAL_GROUP),
1013             FLAG_MOD_REPLACE, "groupType")
1014         ldb.modify(m)
1015
1016         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1017                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1018         self.assertTrue(len(res1) == 1)
1019         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1020                           ATYPE_SECURITY_GLOBAL_GROUP)
1021
1022         # Change to "local" (shouldn't work)
1023
1024         try:
1025             m = Message()
1026             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1027             m["groupType"] = MessageElement(
1028                 str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
1029                 FLAG_MOD_REPLACE, "groupType")
1030             ldb.modify(m)
1031             self.fail()
1032         except LdbError as e40:
1033             (num, _) = e40.args
1034             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1035
1036         # Change to "universal"
1037
1038         m = Message()
1039         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1040         m["groupType"] = MessageElement(
1041             str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1042             FLAG_MOD_REPLACE, "groupType")
1043         ldb.modify(m)
1044
1045         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1046                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1047         self.assertTrue(len(res1) == 1)
1048         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1049                           ATYPE_SECURITY_UNIVERSAL_GROUP)
1050
1051         # Change back to "global"
1052
1053         m = Message()
1054         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1055         m["groupType"] = MessageElement(
1056             str(GTYPE_SECURITY_GLOBAL_GROUP),
1057             FLAG_MOD_REPLACE, "groupType")
1058         ldb.modify(m)
1059
1060         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1061                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1062         self.assertTrue(len(res1) == 1)
1063         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1064                           ATYPE_SECURITY_GLOBAL_GROUP)
1065
1066         # Change back to "universal"
1067
1068         m = Message()
1069         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1070         m["groupType"] = MessageElement(
1071             str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1072             FLAG_MOD_REPLACE, "groupType")
1073         ldb.modify(m)
1074
1075         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1076                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1077         self.assertTrue(len(res1) == 1)
1078         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1079                           ATYPE_SECURITY_UNIVERSAL_GROUP)
1080
1081         # Change to "local"
1082
1083         m = Message()
1084         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1085         m["groupType"] = MessageElement(
1086             str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
1087             FLAG_MOD_REPLACE, "groupType")
1088         ldb.modify(m)
1089
1090         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1091                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1092         self.assertTrue(len(res1) == 1)
1093         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1094                           ATYPE_SECURITY_LOCAL_GROUP)
1095
1096         # Change to "global" (shouldn't work)
1097
1098         try:
1099             m = Message()
1100             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1101             m["groupType"] = MessageElement(
1102                 str(GTYPE_SECURITY_GLOBAL_GROUP),
1103                 FLAG_MOD_REPLACE, "groupType")
1104             ldb.modify(m)
1105             self.fail()
1106         except LdbError as e41:
1107             (num, _) = e41.args
1108             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1109
1110         # Change to "builtin local" (shouldn't work)
1111
1112         try:
1113             m = Message()
1114             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1115             m["groupType"] = MessageElement(
1116                 str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1117                 FLAG_MOD_REPLACE, "groupType")
1118             ldb.modify(m)
1119             self.fail()
1120         except LdbError as e42:
1121             (num, _) = e42.args
1122             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1123
1124         m = Message()
1125         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1126
1127         # Change back to "universal"
1128
1129         m = Message()
1130         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1131         m["groupType"] = MessageElement(
1132             str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1133             FLAG_MOD_REPLACE, "groupType")
1134         ldb.modify(m)
1135
1136         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1137                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1138         self.assertTrue(len(res1) == 1)
1139         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1140                           ATYPE_SECURITY_UNIVERSAL_GROUP)
1141
1142         # Change to "builtin local" (shouldn't work)
1143
1144         try:
1145             m = Message()
1146             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1147             m["groupType"] = MessageElement(
1148                 str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1149                 FLAG_MOD_REPLACE, "groupType")
1150             ldb.modify(m)
1151             self.fail()
1152         except LdbError as e43:
1153             (num, _) = e43.args
1154             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1155
1156         # Change back to "global"
1157
1158         m = Message()
1159         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1160         m["groupType"] = MessageElement(
1161             str(GTYPE_SECURITY_GLOBAL_GROUP),
1162             FLAG_MOD_REPLACE, "groupType")
1163         ldb.modify(m)
1164
1165         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1166                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1167         self.assertTrue(len(res1) == 1)
1168         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1169                           ATYPE_SECURITY_GLOBAL_GROUP)
1170
1171         # Change to "builtin local" (shouldn't work)
1172
1173         try:
1174             m = Message()
1175             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1176             m["groupType"] = MessageElement(
1177                 str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1178                 FLAG_MOD_REPLACE, "groupType")
1179             ldb.modify(m)
1180             self.fail()
1181         except LdbError as e44:
1182             (num, _) = e44.args
1183             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1184
1185         # Distribution groups
1186
1187         # Default is "global group"
1188
1189         m = Message()
1190         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1191         m["groupType"] = MessageElement(
1192             str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1193             FLAG_MOD_REPLACE, "groupType")
1194         ldb.modify(m)
1195
1196         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1197                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1198         self.assertTrue(len(res1) == 1)
1199         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1200                           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1201
1202         # Change to local (shouldn't work)
1203
1204         try:
1205             m = Message()
1206             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1207             m["groupType"] = MessageElement(
1208                 str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1209                 FLAG_MOD_REPLACE, "groupType")
1210             ldb.modify(m)
1211             self.fail()
1212         except LdbError as e45:
1213             (num, _) = e45.args
1214             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1215
1216         # Change to "universal"
1217
1218         m = Message()
1219         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1220         m["groupType"] = MessageElement(
1221             str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1222             FLAG_MOD_REPLACE, "groupType")
1223         ldb.modify(m)
1224
1225         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1226                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1227         self.assertTrue(len(res1) == 1)
1228         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1229                           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1230
1231         # Change back to "global"
1232
1233         m = Message()
1234         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1235         m["groupType"] = MessageElement(
1236             str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1237             FLAG_MOD_REPLACE, "groupType")
1238         ldb.modify(m)
1239
1240         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1241                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1242         self.assertTrue(len(res1) == 1)
1243         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1244                           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1245
1246         # Change back to "universal"
1247
1248         m = Message()
1249         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1250         m["groupType"] = MessageElement(
1251             str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1252             FLAG_MOD_REPLACE, "groupType")
1253         ldb.modify(m)
1254
1255         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1256                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1257         self.assertTrue(len(res1) == 1)
1258         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1259                           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1260
1261         # Change to "local"
1262
1263         m = Message()
1264         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1265         m["groupType"] = MessageElement(
1266             str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1267             FLAG_MOD_REPLACE, "groupType")
1268         ldb.modify(m)
1269
1270         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1271                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1272         self.assertTrue(len(res1) == 1)
1273         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1274                           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1275
1276         # Change to "global" (shouldn't work)
1277
1278         try:
1279             m = Message()
1280             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1281             m["groupType"] = MessageElement(
1282                 str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1283                 FLAG_MOD_REPLACE, "groupType")
1284             ldb.modify(m)
1285             self.fail()
1286         except LdbError as e46:
1287             (num, _) = e46.args
1288             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1289
1290         # Change back to "universal"
1291
1292         # Try to add invalid member to group 1 - should be denied
1293         m = Message()
1294         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1295         m["member"] = MessageElement(
1296             "cn=ldaptestuser3,cn=users," + self.base_dn,
1297             FLAG_MOD_ADD, "member")
1298         try:
1299             ldb.modify(m)
1300             self.fail()
1301         except LdbError as e47:
1302             (num, _) = e47.args
1303             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1304
1305         # Make group 2 secondary
1306         m = Message()
1307         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1308         m["groupType"] = MessageElement(
1309             str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1310             FLAG_MOD_REPLACE, "groupType")
1311         ldb.modify(m)
1312
1313         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1314                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1315         self.assertTrue(len(res1) == 1)
1316         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1317                           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1318
1319         # Change back to "global"
1320
1321         m = Message()
1322         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1323         m["groupType"] = MessageElement(
1324             str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1325             FLAG_MOD_REPLACE, "groupType")
1326         ldb.modify(m)
1327
1328         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1329                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1330         self.assertTrue(len(res1) == 1)
1331         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1332                           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1333
1334         # Both group types: this performs only random checks - all possibilities
1335         # would require too much code.
1336
1337         # Default is "global group"
1338
1339         m = Message()
1340         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1341         m["groupType"] = MessageElement(
1342             str(GTYPE_SECURITY_GLOBAL_GROUP),
1343             FLAG_MOD_REPLACE, "groupType")
1344         ldb.modify(m)
1345
1346         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1347                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1348         self.assertTrue(len(res1) == 1)
1349         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1350                           ATYPE_SECURITY_GLOBAL_GROUP)
1351
1352         # Change to "local" (shouldn't work)
1353
1354         try:
1355             m = Message()
1356             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1357             m["groupType"] = MessageElement(
1358                 str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1359                 FLAG_MOD_REPLACE, "groupType")
1360             ldb.modify(m)
1361             self.fail()
1362         except LdbError as e48:
1363             (num, _) = e48.args
1364             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1365
1366         # Change to "universal"
1367
1368         m = Message()
1369         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1370         m["groupType"] = MessageElement(
1371             str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1372             FLAG_MOD_REPLACE, "groupType")
1373         ldb.modify(m)
1374
1375         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1376                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1377         self.assertTrue(len(res1) == 1)
1378         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1379                           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1380
1381         # Change back to "global"
1382
1383         m = Message()
1384         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1385         m["groupType"] = MessageElement(
1386             str(GTYPE_SECURITY_GLOBAL_GROUP),
1387             FLAG_MOD_REPLACE, "groupType")
1388         ldb.modify(m)
1389
1390         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1391                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1392         self.assertTrue(len(res1) == 1)
1393         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1394                           ATYPE_SECURITY_GLOBAL_GROUP)
1395
1396         # Change back to "universal"
1397
1398         m = Message()
1399         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1400         m["groupType"] = MessageElement(
1401             str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1402             FLAG_MOD_REPLACE, "groupType")
1403         ldb.modify(m)
1404
1405         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1406                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1407         self.assertTrue(len(res1) == 1)
1408         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1409                           ATYPE_SECURITY_UNIVERSAL_GROUP)
1410
1411         # Change to "local"
1412
1413         m = Message()
1414         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1415         m["groupType"] = MessageElement(
1416             str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1417             FLAG_MOD_REPLACE, "groupType")
1418         ldb.modify(m)
1419
1420         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1421                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1422         self.assertTrue(len(res1) == 1)
1423         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1424                           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1425
1426         # Change to "global" (shouldn't work)
1427
1428         try:
1429             m = Message()
1430             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1431             m["groupType"] = MessageElement(
1432                 str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1433                 FLAG_MOD_REPLACE, "groupType")
1434             ldb.modify(m)
1435             self.fail()
1436         except LdbError as e49:
1437             (num, _) = e49.args
1438             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1439
1440         # Change back to "universal"
1441
1442         m = Message()
1443         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1444         m["groupType"] = MessageElement(
1445             str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1446             FLAG_MOD_REPLACE, "groupType")
1447         ldb.modify(m)
1448
1449         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1450                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1451         self.assertTrue(len(res1) == 1)
1452         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1453                           ATYPE_SECURITY_UNIVERSAL_GROUP)
1454
1455         # Change back to "global"
1456
1457         m = Message()
1458         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1459         m["groupType"] = MessageElement(
1460             str(GTYPE_SECURITY_GLOBAL_GROUP),
1461             FLAG_MOD_REPLACE, "groupType")
1462         ldb.modify(m)
1463
1464         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1465                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1466         self.assertTrue(len(res1) == 1)
1467         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1468                           ATYPE_SECURITY_GLOBAL_GROUP)
1469
1470         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1471
1472     def test_pwdLastSet(self):
1473         """Test the pwdLastSet behaviour"""
1474         print("Testing pwdLastSet behaviour\n")
1475
1476         ldb.add({
1477             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1478             "objectclass": "user",
1479             "pwdLastSet": "0"})
1480
1481         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1482                           scope=SCOPE_BASE,
1483                           attrs=["sAMAccountType", "userAccountControl", "pwdLastSet"])
1484         self.assertTrue(len(res1) == 1)
1485         self.assertEqual(int(res1[0]["sAMAccountType"][0]),
1486                          ATYPE_NORMAL_ACCOUNT)
1487         self.assertEqual(int(res1[0]["userAccountControl"][0]),
1488                          UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD)
1489         self.assertEqual(int(res1[0]["pwdLastSet"][0]), 0)
1490         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1491
1492         ldb.add({
1493             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1494             "objectclass": "user",
1495             "pwdLastSet": "-1"})
1496
1497         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1498                           scope=SCOPE_BASE,
1499                           attrs=["sAMAccountType", "userAccountControl", "pwdLastSet"])
1500         self.assertTrue(len(res1) == 1)
1501         self.assertEqual(int(res1[0]["sAMAccountType"][0]),
1502                          ATYPE_NORMAL_ACCOUNT)
1503         self.assertEqual(int(res1[0]["userAccountControl"][0]),
1504                          UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD)
1505         self.assertNotEqual(int(res1[0]["pwdLastSet"][0]), 0)
1506         lastset = int(res1[0]["pwdLastSet"][0])
1507         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1508
1509         try:
1510             ldb.add({
1511                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1512                 "objectclass": "user",
1513                 "pwdLastSet": str(1)})
1514             self.fail()
1515         except LdbError as e50:
1516             (num, msg) = e50.args
1517             self.assertEquals(num, ERR_OTHER)
1518             self.assertTrue('00000057' in msg)
1519
1520         try:
1521             ldb.add({
1522                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1523                 "objectclass": "user",
1524                 "pwdLastSet": str(lastset)})
1525             self.fail()
1526         except LdbError as e51:
1527             (num, msg) = e51.args
1528             self.assertEquals(num, ERR_OTHER)
1529             self.assertTrue('00000057' in msg)
1530
1531         ldb.add({
1532             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1533             "objectclass": "user"})
1534
1535         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1536                           scope=SCOPE_BASE,
1537                           attrs=["sAMAccountType", "userAccountControl", "pwdLastSet"])
1538         self.assertTrue(len(res1) == 1)
1539         self.assertEqual(int(res1[0]["sAMAccountType"][0]),
1540                          ATYPE_NORMAL_ACCOUNT)
1541         self.assertEqual(int(res1[0]["userAccountControl"][0]),
1542                          UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD)
1543         self.assertEqual(int(res1[0]["pwdLastSet"][0]), 0)
1544
1545         m = Message()
1546         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1547         m["pls1"] = MessageElement(str(0),
1548                                    FLAG_MOD_REPLACE,
1549                                    "pwdLastSet")
1550         ldb.modify(m)
1551
1552         m = Message()
1553         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1554         m["pls1"] = MessageElement(str(0),
1555                                    FLAG_MOD_DELETE,
1556                                    "pwdLastSet")
1557         m["pls2"] = MessageElement(str(0),
1558                                    FLAG_MOD_ADD,
1559                                    "pwdLastSet")
1560         ldb.modify(m)
1561
1562         m = Message()
1563         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1564         m["pls1"] = MessageElement(str(-1),
1565                                    FLAG_MOD_REPLACE,
1566                                    "pwdLastSet")
1567         ldb.modify(m)
1568         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1569                           scope=SCOPE_BASE,
1570                           attrs=["sAMAccountType", "userAccountControl", "pwdLastSet"])
1571         self.assertTrue(len(res1) == 1)
1572         self.assertEqual(int(res1[0]["sAMAccountType"][0]),
1573                          ATYPE_NORMAL_ACCOUNT)
1574         self.assertEqual(int(res1[0]["userAccountControl"][0]),
1575                          UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD)
1576         self.assertGreater(int(res1[0]["pwdLastSet"][0]), lastset)
1577         lastset = int(res1[0]["pwdLastSet"][0])
1578
1579         try:
1580             m = Message()
1581             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1582             m["pls1"] = MessageElement(str(0),
1583                                        FLAG_MOD_DELETE,
1584                                        "pwdLastSet")
1585             m["pls2"] = MessageElement(str(0),
1586                                        FLAG_MOD_ADD,
1587                                        "pwdLastSet")
1588             ldb.modify(m)
1589             self.fail()
1590         except LdbError as e52:
1591             (num, msg) = e52.args
1592             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
1593             self.assertTrue('00002085' in msg)
1594
1595         try:
1596             m = Message()
1597             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1598             m["pls1"] = MessageElement(str(-1),
1599                                        FLAG_MOD_DELETE,
1600                                        "pwdLastSet")
1601             m["pls2"] = MessageElement(str(0),
1602                                        FLAG_MOD_ADD,
1603                                        "pwdLastSet")
1604             ldb.modify(m)
1605             self.fail()
1606         except LdbError as e53:
1607             (num, msg) = e53.args
1608             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
1609             self.assertTrue('00002085' in msg)
1610
1611         m = Message()
1612         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1613         m["pls1"] = MessageElement(str(lastset),
1614                                    FLAG_MOD_DELETE,
1615                                    "pwdLastSet")
1616         m["pls2"] = MessageElement(str(-1),
1617                                    FLAG_MOD_ADD,
1618                                    "pwdLastSet")
1619         time.sleep(0.2)
1620         ldb.modify(m)
1621         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1622                           scope=SCOPE_BASE,
1623                           attrs=["sAMAccountType", "userAccountControl", "pwdLastSet"])
1624         self.assertTrue(len(res1) == 1)
1625         self.assertEqual(int(res1[0]["sAMAccountType"][0]),
1626                          ATYPE_NORMAL_ACCOUNT)
1627         self.assertEqual(int(res1[0]["userAccountControl"][0]),
1628                          UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD)
1629         self.assertEqual(int(res1[0]["pwdLastSet"][0]), lastset)
1630
1631         try:
1632             m = Message()
1633             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1634             m["pls1"] = MessageElement(str(lastset),
1635                                        FLAG_MOD_DELETE,
1636                                        "pwdLastSet")
1637             m["pls2"] = MessageElement(str(lastset),
1638                                        FLAG_MOD_ADD,
1639                                        "pwdLastSet")
1640             ldb.modify(m)
1641             self.fail()
1642         except LdbError as e54:
1643             (num, msg) = e54.args
1644             self.assertEquals(num, ERR_OTHER)
1645             self.assertTrue('00000057' in msg)
1646
1647         m = Message()
1648         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1649         m["pls1"] = MessageElement(str(lastset),
1650                                    FLAG_MOD_DELETE,
1651                                    "pwdLastSet")
1652         m["pls2"] = MessageElement(str(0),
1653                                    FLAG_MOD_ADD,
1654                                    "pwdLastSet")
1655         ldb.modify(m)
1656         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1657                           scope=SCOPE_BASE,
1658                           attrs=["sAMAccountType", "userAccountControl", "pwdLastSet"])
1659         self.assertTrue(len(res1) == 1)
1660         self.assertEqual(int(res1[0]["sAMAccountType"][0]),
1661                          ATYPE_NORMAL_ACCOUNT)
1662         self.assertEqual(int(res1[0]["userAccountControl"][0]),
1663                          UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD)
1664         uac = int(res1[0]["userAccountControl"][0])
1665         self.assertEqual(int(res1[0]["pwdLastSet"][0]), 0)
1666
1667         m = Message()
1668         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1669         m["uac1"] = MessageElement(str(uac |UF_PASSWORD_EXPIRED),
1670                                    FLAG_MOD_REPLACE,
1671                                    "userAccountControl")
1672         ldb.modify(m)
1673         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1674                           scope=SCOPE_BASE,
1675                           attrs=["sAMAccountType", "userAccountControl", "pwdLastSet"])
1676         self.assertTrue(len(res1) == 1)
1677         self.assertEqual(int(res1[0]["sAMAccountType"][0]),
1678                          ATYPE_NORMAL_ACCOUNT)
1679         self.assertEqual(int(res1[0]["userAccountControl"][0]),
1680                          UF_NORMAL_ACCOUNT | UF_ACCOUNTDISABLE | UF_PASSWD_NOTREQD)
1681         self.assertEqual(int(res1[0]["pwdLastSet"][0]), 0)
1682
1683         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1684
1685     def test_ldap_bind_must_change_pwd(self):
1686         """Test the error messages for failing LDAP binds"""
1687         print("Test the error messages for failing LDAP binds\n")
1688
1689         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1690
1691         def format_error_msg(hresult_v, dsid_v, werror_v):
1692             #
1693             # There are 4 lower case hex digits following 'v' at the end,
1694             # but different Windows Versions return different values:
1695             #
1696             # Windows 2008R2 uses 'v1db1'
1697             # Windows 2012R2 uses 'v2580'
1698             #
1699             return "%08X: LdapErr: DSID-%08X, comment: AcceptSecurityContext error, data %x, v" % (
1700                     hresult_v, dsid_v, werror_v)
1701
1702         HRES_SEC_E_LOGON_DENIED = 0x8009030C
1703         HRES_SEC_E_INVALID_TOKEN = 0x80090308
1704
1705         sasl_bind_dsid = 0x0C0904DC
1706         simple_bind_dsid = 0x0C0903A9
1707
1708         error_msg_sasl_wrong_pw = format_error_msg(
1709                                 HRES_SEC_E_LOGON_DENIED,
1710                                 sasl_bind_dsid,
1711                                 werror.WERR_LOGON_FAILURE)
1712         error_msg_sasl_must_change = format_error_msg(
1713                                 HRES_SEC_E_LOGON_DENIED,
1714                                 sasl_bind_dsid,
1715                                 werror.WERR_PASSWORD_MUST_CHANGE)
1716         error_msg_simple_wrong_pw = format_error_msg(
1717                                 HRES_SEC_E_INVALID_TOKEN,
1718                                 simple_bind_dsid,
1719                                 werror.WERR_LOGON_FAILURE)
1720         error_msg_simple_must_change = format_error_msg(
1721                                 HRES_SEC_E_INVALID_TOKEN,
1722                                 simple_bind_dsid,
1723                                 werror.WERR_PASSWORD_MUST_CHANGE)
1724
1725         username = "ldaptestuser"
1726         password = "thatsAcomplPASS2"
1727         utf16pw = unicode('"' + password.encode('utf-8') + '"', 'utf-8').encode('utf-16-le')
1728
1729         ldb.add({
1730             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1731             "objectclass": "user",
1732             "sAMAccountName": username,
1733             "userAccountControl": str(UF_NORMAL_ACCOUNT),
1734             "unicodePwd": utf16pw,
1735         })
1736
1737         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1738                           scope=SCOPE_BASE,
1739                           attrs=["sAMAccountName", "sAMAccountType", "userAccountControl", "pwdLastSet"])
1740         self.assertTrue(len(res1) == 1)
1741         self.assertEqual(res1[0]["sAMAccountName"][0], username)
1742         self.assertEqual(int(res1[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
1743         self.assertEqual(int(res1[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT)
1744         self.assertNotEqual(int(res1[0]["pwdLastSet"][0]), 0)
1745
1746         # Open a second LDB connection with the user credentials. Use the
1747         # command line credentials for informations like the domain, the realm
1748         # and the workstation.
1749         sasl_creds = Credentials()
1750         sasl_creds.set_username(username)
1751         sasl_creds.set_password(password)
1752         sasl_creds.set_domain(creds.get_domain())
1753         sasl_creds.set_workstation(creds.get_workstation())
1754         sasl_creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
1755         sasl_creds.set_kerberos_state(DONT_USE_KERBEROS)
1756
1757         sasl_wrong_creds = Credentials()
1758         sasl_wrong_creds.set_username(username)
1759         sasl_wrong_creds.set_password("wrong")
1760         sasl_wrong_creds.set_domain(creds.get_domain())
1761         sasl_wrong_creds.set_workstation(creds.get_workstation())
1762         sasl_wrong_creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
1763         sasl_wrong_creds.set_kerberos_state(DONT_USE_KERBEROS)
1764
1765         simple_creds = Credentials()
1766         simple_creds.set_bind_dn("cn=ldaptestuser,cn=users," + self.base_dn)
1767         simple_creds.set_username(username)
1768         simple_creds.set_password(password)
1769         simple_creds.set_domain(creds.get_domain())
1770         simple_creds.set_workstation(creds.get_workstation())
1771         simple_creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
1772         simple_creds.set_kerberos_state(DONT_USE_KERBEROS)
1773
1774         simple_wrong_creds = Credentials()
1775         simple_wrong_creds.set_bind_dn("cn=ldaptestuser,cn=users," + self.base_dn)
1776         simple_wrong_creds.set_username(username)
1777         simple_wrong_creds.set_password("wrong")
1778         simple_wrong_creds.set_domain(creds.get_domain())
1779         simple_wrong_creds.set_workstation(creds.get_workstation())
1780         simple_wrong_creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
1781         simple_wrong_creds.set_kerberos_state(DONT_USE_KERBEROS)
1782
1783         sasl_ldb = SamDB(url=host, credentials=sasl_creds, lp=lp)
1784         self.assertIsNotNone(sasl_ldb)
1785         sasl_ldb = None
1786
1787         requires_strong_auth = False
1788         try:
1789             simple_ldb = SamDB(url=host, credentials=simple_creds, lp=lp)
1790             self.assertIsNotNone(simple_ldb)
1791             simple_ldb = None
1792         except LdbError as e55:
1793             (num, msg) = e55.args
1794             if num != ERR_STRONG_AUTH_REQUIRED:
1795                 raise
1796             requires_strong_auth = True
1797
1798         def assertLDAPErrorMsg(msg, expected_msg):
1799             self.assertTrue(expected_msg in msg,
1800                             "msg[%s] does not contain expected[%s]" % (
1801                                 msg, expected_msg))
1802
1803         try:
1804             ldb_fail = SamDB(url=host, credentials=sasl_wrong_creds, lp=lp)
1805             self.fail()
1806         except LdbError as e56:
1807             (num, msg) = e56.args
1808             self.assertEquals(num, ERR_INVALID_CREDENTIALS)
1809             self.assertTrue(error_msg_sasl_wrong_pw in msg)
1810
1811         if not requires_strong_auth:
1812             try:
1813                 ldb_fail = SamDB(url=host, credentials=simple_wrong_creds, lp=lp)
1814                 self.fail()
1815             except LdbError as e4:
1816                 (num, msg) = e4.args
1817                 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
1818                 assertLDAPErrorMsg(msg, error_msg_simple_wrong_pw)
1819
1820         m = Message()
1821         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1822         m["pls1"] = MessageElement(str(0),
1823                                    FLAG_MOD_REPLACE,
1824                                    "pwdLastSet")
1825         ldb.modify(m)
1826
1827         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1828                           scope=SCOPE_BASE, attrs=["pwdLastSet"])
1829         self.assertEqual(int(res1[0]["pwdLastSet"][0]), 0)
1830
1831         try:
1832             ldb_fail = SamDB(url=host, credentials=sasl_wrong_creds, lp=lp)
1833             self.fail()
1834         except LdbError as e57:
1835             (num, msg) = e57.args
1836             self.assertEquals(num, ERR_INVALID_CREDENTIALS)
1837             assertLDAPErrorMsg(msg, error_msg_sasl_wrong_pw)
1838
1839         try:
1840             ldb_fail = SamDB(url=host, credentials=sasl_creds, lp=lp)
1841             self.fail()
1842         except LdbError as e58:
1843             (num, msg) = e58.args
1844             self.assertEquals(num, ERR_INVALID_CREDENTIALS)
1845             assertLDAPErrorMsg(msg, error_msg_sasl_must_change)
1846
1847         if not requires_strong_auth:
1848             try:
1849                 ldb_fail = SamDB(url=host, credentials=simple_wrong_creds, lp=lp)
1850                 self.fail()
1851             except LdbError as e5:
1852                 (num, msg) = e5.args
1853                 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
1854                 assertLDAPErrorMsg(msg, error_msg_simple_wrong_pw)
1855
1856             try:
1857                 ldb_fail = SamDB(url=host, credentials=simple_creds, lp=lp)
1858                 self.fail()
1859             except LdbError as e6:
1860                 (num, msg) = e6.args
1861                 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
1862                 assertLDAPErrorMsg(msg, error_msg_simple_must_change)
1863
1864         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1865
1866     def test_userAccountControl(self):
1867         """Test the userAccountControl behaviour"""
1868         print("Testing userAccountControl behaviour\n")
1869
1870         # With a user object
1871
1872         # Add operation
1873
1874         # As user you can only set a normal account.
1875         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1876         # password yet.
1877         # With SYSTEM rights you can set a interdomain trust account.
1878
1879         ldb.add({
1880             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1881             "objectclass": "user",
1882             "userAccountControl": "0"})
1883
1884         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1885                           scope=SCOPE_BASE,
1886                           attrs=["sAMAccountType", "userAccountControl"])
1887         self.assertTrue(len(res1) == 1)
1888         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1889                           ATYPE_NORMAL_ACCOUNT)
1890         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
1891         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0)
1892         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1893
1894         ldb.add({
1895             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1896             "objectclass": "user",
1897             "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1898         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1899
1900         ldb.add({
1901             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1902             "objectclass": "user",
1903             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1904
1905         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1906                           scope=SCOPE_BASE,
1907                           attrs=["sAMAccountType", "userAccountControl"])
1908         self.assertTrue(len(res1) == 1)
1909         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1910                           ATYPE_NORMAL_ACCOUNT)
1911         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
1912         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1913
1914         ldb.add({
1915             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1916             "objectclass": "user",
1917             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_LOCKOUT | UF_PASSWORD_EXPIRED)})
1918
1919         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1920                           scope=SCOPE_BASE,
1921                           attrs=["sAMAccountType", "userAccountControl", "lockoutTime", "pwdLastSet"])
1922         self.assertTrue(len(res1) == 1)
1923         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1924                           ATYPE_NORMAL_ACCOUNT)
1925         self.assertTrue(int(res1[0]["userAccountControl"][0]) & (UF_LOCKOUT | UF_PASSWORD_EXPIRED) == 0)
1926         self.assertFalse("lockoutTime" in res1[0])
1927         self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
1928         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1929
1930         try:
1931             ldb.add({
1932                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1933                 "objectclass": "user",
1934                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1935             self.fail()
1936         except LdbError as e59:
1937             (num, _) = e59.args
1938             self.assertEquals(num, ERR_OTHER)
1939         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1940
1941         try:
1942             ldb.add({
1943                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1944                 "objectclass": "user",
1945                 "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1946             self.fail()
1947         except LdbError as e60:
1948             (num, _) = e60.args
1949             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1950         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1951
1952         try:
1953             ldb.add({
1954                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1955                 "objectclass": "user",
1956                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1957         except LdbError as e61:
1958             (num, _) = e61.args
1959             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1960         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1961
1962         try:
1963             ldb.add({
1964                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1965                 "objectclass": "user",
1966                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)})
1967         except LdbError as e62:
1968             (num, _) = e62.args
1969             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1970         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1971
1972         try:
1973             ldb.add({
1974                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1975                 "objectclass": "user",
1976                 "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1977             self.fail()
1978         except LdbError as e63:
1979             (num, _) = e63.args
1980             self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1981         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1982
1983         # Modify operation
1984
1985         ldb.add({
1986             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1987             "objectclass": "user"})
1988
1989         # After creation we should have a normal account
1990         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1991                           scope=SCOPE_BASE,
1992                           attrs=["sAMAccountType", "userAccountControl"])
1993         self.assertTrue(len(res1) == 1)
1994         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1995                           ATYPE_NORMAL_ACCOUNT)
1996         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
1997
1998         # As user you can only switch from a normal account to a workstation
1999         # trust account and back.
2000         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
2001         # password yet.
2002         # With SYSTEM rights you can switch to a interdomain trust account.
2003
2004         # Invalid attribute
2005         try:
2006             m = Message()
2007             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2008             m["userAccountControl"] = MessageElement("0",
2009                                                      FLAG_MOD_REPLACE, "userAccountControl")
2010             ldb.modify(m)
2011         except LdbError as e64:
2012             (num, _) = e64.args
2013             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2014
2015         try:
2016             m = Message()
2017             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2018             m["userAccountControl"] = MessageElement(
2019                 str(UF_NORMAL_ACCOUNT),
2020                 FLAG_MOD_REPLACE, "userAccountControl")
2021             ldb.modify(m)
2022         except LdbError as e65:
2023             (num, _) = e65.args
2024             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2025
2026         m = Message()
2027         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2028         m["userAccountControl"] = MessageElement(
2029             str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2030             FLAG_MOD_REPLACE, "userAccountControl")
2031         ldb.modify(m)
2032
2033         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2034                           scope=SCOPE_BASE,
2035                           attrs=["sAMAccountType", "userAccountControl"])
2036         self.assertTrue(len(res1) == 1)
2037         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2038                           ATYPE_NORMAL_ACCOUNT)
2039         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
2040
2041         m = Message()
2042         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2043         m["userAccountControl"] = MessageElement(
2044             str(UF_ACCOUNTDISABLE),
2045             FLAG_MOD_REPLACE, "userAccountControl")
2046         ldb.modify(m)
2047
2048         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2049                           scope=SCOPE_BASE,
2050                           attrs=["sAMAccountType", "userAccountControl"])
2051         self.assertTrue(len(res1) == 1)
2052         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2053                           ATYPE_NORMAL_ACCOUNT)
2054         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_NORMAL_ACCOUNT != 0)
2055         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
2056
2057         m = Message()
2058         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2059         m["lockoutTime"] = MessageElement(str(samba.unix2nttime(0)), FLAG_MOD_REPLACE, "lockoutTime")
2060         m["pwdLastSet"] = MessageElement(str(samba.unix2nttime(0)), FLAG_MOD_REPLACE, "pwdLastSet")
2061         ldb.modify(m)
2062
2063         m = Message()
2064         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2065         m["userAccountControl"] = MessageElement(
2066             str(UF_LOCKOUT | UF_PASSWORD_EXPIRED),
2067             FLAG_MOD_REPLACE, "userAccountControl")
2068         ldb.modify(m)
2069
2070         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2071                           scope=SCOPE_BASE,
2072                           attrs=["sAMAccountType", "userAccountControl", "lockoutTime", "pwdLastSet"])
2073         self.assertTrue(len(res1) == 1)
2074         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2075                           ATYPE_NORMAL_ACCOUNT)
2076         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_NORMAL_ACCOUNT != 0)
2077         self.assertTrue(int(res1[0]["userAccountControl"][0]) & (UF_LOCKOUT | UF_PASSWORD_EXPIRED) == 0)
2078         self.assertTrue(int(res1[0]["lockoutTime"][0]) == 0)
2079         self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
2080
2081         try:
2082             m = Message()
2083             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2084             m["userAccountControl"] = MessageElement(
2085                 str(UF_TEMP_DUPLICATE_ACCOUNT),
2086                 FLAG_MOD_REPLACE, "userAccountControl")
2087             ldb.modify(m)
2088             self.fail()
2089         except LdbError as e66:
2090             (num, _) = e66.args
2091             self.assertEquals(num, ERR_OTHER)
2092
2093         try:
2094             m = Message()
2095             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2096             m["userAccountControl"] = MessageElement(
2097                 str(UF_SERVER_TRUST_ACCOUNT),
2098                 FLAG_MOD_REPLACE, "userAccountControl")
2099             ldb.modify(m)
2100             self.fail()
2101         except LdbError as e67:
2102             (num, _) = e67.args
2103             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2104
2105         m = Message()
2106         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2107         m["userAccountControl"] = MessageElement(
2108             str(UF_WORKSTATION_TRUST_ACCOUNT),
2109             FLAG_MOD_REPLACE, "userAccountControl")
2110         ldb.modify(m)
2111
2112         try:
2113             m = Message()
2114             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2115             m["userAccountControl"] = MessageElement(
2116                 str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT),
2117                 FLAG_MOD_REPLACE, "userAccountControl")
2118             ldb.modify(m)
2119             self.fail()
2120         except LdbError as e68:
2121             (num, _) = e68.args
2122             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2123
2124         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2125                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2126         self.assertTrue(len(res1) == 1)
2127         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2128                           ATYPE_WORKSTATION_TRUST)
2129
2130         m = Message()
2131         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2132         m["userAccountControl"] = MessageElement(
2133             str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2134             FLAG_MOD_REPLACE, "userAccountControl")
2135         ldb.modify(m)
2136
2137         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2138                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2139         self.assertTrue(len(res1) == 1)
2140         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2141                           ATYPE_NORMAL_ACCOUNT)
2142
2143         try:
2144             m = Message()
2145             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2146             m["userAccountControl"] = MessageElement(
2147                 str(UF_INTERDOMAIN_TRUST_ACCOUNT),
2148                 FLAG_MOD_REPLACE, "userAccountControl")
2149             ldb.modify(m)
2150             self.fail()
2151         except LdbError as e69:
2152             (num, _) = e69.args
2153             self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
2154
2155         # With a computer object
2156
2157         # Add operation
2158
2159         # As computer you can set a normal account and a server trust account.
2160         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
2161         # password yet.
2162         # With SYSTEM rights you can set a interdomain trust account.
2163
2164         ldb.add({
2165             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2166             "objectclass": "computer",
2167             "userAccountControl": "0"})
2168
2169         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2170                           scope=SCOPE_BASE,
2171                           attrs=["sAMAccountType", "userAccountControl"])
2172         self.assertTrue(len(res1) == 1)
2173         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2174                           ATYPE_NORMAL_ACCOUNT)
2175         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
2176         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0)
2177         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2178
2179         ldb.add({
2180             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2181             "objectclass": "computer",
2182             "userAccountControl": str(UF_NORMAL_ACCOUNT)})
2183         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2184
2185         ldb.add({
2186             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2187             "objectclass": "computer",
2188             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
2189
2190         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2191                           scope=SCOPE_BASE,
2192                           attrs=["sAMAccountType", "userAccountControl"])
2193         self.assertTrue(len(res1) == 1)
2194         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2195                           ATYPE_NORMAL_ACCOUNT)
2196         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
2197         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2198
2199         ldb.add({
2200             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2201             "objectclass": "computer",
2202             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_LOCKOUT | UF_PASSWORD_EXPIRED)})
2203
2204         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2205                           scope=SCOPE_BASE,
2206                           attrs=["sAMAccountType", "userAccountControl", "lockoutTime", "pwdLastSet"])
2207         self.assertTrue(len(res1) == 1)
2208         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2209                           ATYPE_NORMAL_ACCOUNT)
2210         self.assertTrue(int(res1[0]["userAccountControl"][0]) & (UF_LOCKOUT | UF_PASSWORD_EXPIRED) == 0)
2211         self.assertFalse("lockoutTime" in res1[0])
2212         self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
2213         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2214
2215         try:
2216             ldb.add({
2217                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2218                 "objectclass": "computer",
2219                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
2220             self.fail()
2221         except LdbError as e70:
2222             (num, _) = e70.args
2223             self.assertEquals(num, ERR_OTHER)
2224         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2225
2226         ldb.add({
2227             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2228             "objectclass": "computer",
2229             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
2230
2231         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2232                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2233         self.assertTrue(len(res1) == 1)
2234         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2235                           ATYPE_WORKSTATION_TRUST)
2236         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2237
2238         try:
2239             ldb.add({
2240                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2241                 "objectclass": "computer",
2242                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
2243         except LdbError as e71:
2244             (num, _) = e71.args
2245             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
2246         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2247
2248         try:
2249             ldb.add({
2250                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2251                 "objectclass": "computer",
2252                 "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
2253             self.fail()
2254         except LdbError as e72:
2255             (num, _) = e72.args
2256             self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
2257         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2258
2259         # Modify operation
2260
2261         ldb.add({
2262             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2263             "objectclass": "computer"})
2264
2265         # After creation we should have a normal account
2266         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2267                           scope=SCOPE_BASE,
2268                           attrs=["sAMAccountType", "userAccountControl"])
2269         self.assertTrue(len(res1) == 1)
2270         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2271                           ATYPE_NORMAL_ACCOUNT)
2272         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
2273
2274         # As computer you can switch from a normal account to a workstation
2275         # or server trust account and back (also swapping between trust
2276         # accounts is allowed).
2277         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
2278         # password yet.
2279         # With SYSTEM rights you can switch to a interdomain trust account.
2280
2281         # Invalid attribute
2282         try:
2283             m = Message()
2284             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2285             m["userAccountControl"] = MessageElement("0",
2286                                                      FLAG_MOD_REPLACE, "userAccountControl")
2287             ldb.modify(m)
2288         except LdbError as e73:
2289             (num, _) = e73.args
2290             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2291
2292         try:
2293             m = Message()
2294             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2295             m["userAccountControl"] = MessageElement(
2296                 str(UF_NORMAL_ACCOUNT),
2297                 FLAG_MOD_REPLACE, "userAccountControl")
2298             ldb.modify(m)
2299         except LdbError as e74:
2300             (num, _) = e74.args
2301             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2302
2303         m = Message()
2304         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2305         m["userAccountControl"] = MessageElement(
2306             str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2307             FLAG_MOD_REPLACE, "userAccountControl")
2308         ldb.modify(m)
2309
2310         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2311                           scope=SCOPE_BASE,
2312                           attrs=["sAMAccountType", "userAccountControl"])
2313         self.assertTrue(len(res1) == 1)
2314         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2315                           ATYPE_NORMAL_ACCOUNT)
2316         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
2317
2318         m = Message()
2319         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2320         m["userAccountControl"] = MessageElement(
2321             str(UF_ACCOUNTDISABLE),
2322             FLAG_MOD_REPLACE, "userAccountControl")
2323         ldb.modify(m)
2324
2325         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2326                           scope=SCOPE_BASE,
2327                           attrs=["sAMAccountType", "userAccountControl"])
2328         self.assertTrue(len(res1) == 1)
2329         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2330                           ATYPE_NORMAL_ACCOUNT)
2331         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_NORMAL_ACCOUNT != 0)
2332         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
2333
2334         m = Message()
2335         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2336         m["lockoutTime"] = MessageElement(str(samba.unix2nttime(0)), FLAG_MOD_REPLACE, "lockoutTime")
2337         m["pwdLastSet"] = MessageElement(str(samba.unix2nttime(0)), FLAG_MOD_REPLACE, "pwdLastSet")
2338         ldb.modify(m)
2339
2340         m = Message()
2341         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2342         m["userAccountControl"] = MessageElement(
2343             str(UF_LOCKOUT | UF_PASSWORD_EXPIRED),
2344             FLAG_MOD_REPLACE, "userAccountControl")
2345         ldb.modify(m)
2346
2347         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2348                           scope=SCOPE_BASE,
2349                           attrs=["sAMAccountType", "userAccountControl", "lockoutTime", "pwdLastSet"])
2350         self.assertTrue(len(res1) == 1)
2351         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2352                           ATYPE_NORMAL_ACCOUNT)
2353         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_NORMAL_ACCOUNT != 0)
2354         self.assertTrue(int(res1[0]["userAccountControl"][0]) & (UF_LOCKOUT | UF_PASSWORD_EXPIRED) == 0)
2355         self.assertTrue(int(res1[0]["lockoutTime"][0]) == 0)
2356         self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
2357
2358         try:
2359             m = Message()
2360             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2361             m["userAccountControl"] = MessageElement(
2362                 str(UF_TEMP_DUPLICATE_ACCOUNT),
2363                 FLAG_MOD_REPLACE, "userAccountControl")
2364             ldb.modify(m)
2365             self.fail()
2366         except LdbError as e75:
2367             (num, _) = e75.args
2368             self.assertEquals(num, ERR_OTHER)
2369
2370         m = Message()
2371         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2372         m["userAccountControl"] = MessageElement(
2373             str(UF_SERVER_TRUST_ACCOUNT),
2374             FLAG_MOD_REPLACE, "userAccountControl")
2375         ldb.modify(m)
2376
2377         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2378                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2379         self.assertTrue(len(res1) == 1)
2380         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2381                           ATYPE_WORKSTATION_TRUST)
2382
2383         m = Message()
2384         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2385         m["userAccountControl"] = MessageElement(
2386             str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2387             FLAG_MOD_REPLACE, "userAccountControl")
2388         ldb.modify(m)
2389
2390         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2391                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2392         self.assertTrue(len(res1) == 1)
2393         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2394                           ATYPE_NORMAL_ACCOUNT)
2395
2396         m = Message()
2397         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2398         m["userAccountControl"] = MessageElement(
2399             str(UF_WORKSTATION_TRUST_ACCOUNT),
2400             FLAG_MOD_REPLACE, "userAccountControl")
2401         ldb.modify(m)
2402
2403         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2404                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2405         self.assertTrue(len(res1) == 1)
2406         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2407                           ATYPE_WORKSTATION_TRUST)
2408
2409         m = Message()
2410         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2411         m["userAccountControl"] = MessageElement(
2412             str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2413             FLAG_MOD_REPLACE, "userAccountControl")
2414         ldb.modify(m)
2415
2416         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2417                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2418         self.assertTrue(len(res1) == 1)
2419         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2420                           ATYPE_NORMAL_ACCOUNT)
2421
2422         m = Message()
2423         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2424         m["userAccountControl"] = MessageElement(
2425             str(UF_SERVER_TRUST_ACCOUNT),
2426             FLAG_MOD_REPLACE, "userAccountControl")
2427         ldb.modify(m)
2428
2429         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2430                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2431         self.assertTrue(len(res1) == 1)
2432         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2433                           ATYPE_WORKSTATION_TRUST)
2434
2435         m = Message()
2436         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2437         m["userAccountControl"] = MessageElement(
2438             str(UF_WORKSTATION_TRUST_ACCOUNT),
2439             FLAG_MOD_REPLACE, "userAccountControl")
2440         ldb.modify(m)
2441
2442         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2443                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
2444         self.assertTrue(len(res1) == 1)
2445         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
2446                           ATYPE_WORKSTATION_TRUST)
2447
2448         try:
2449             m = Message()
2450             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2451             m["userAccountControl"] = MessageElement(
2452                 str(UF_INTERDOMAIN_TRUST_ACCOUNT),
2453                 FLAG_MOD_REPLACE, "userAccountControl")
2454             ldb.modify(m)
2455             self.fail()
2456         except LdbError as e76:
2457             (num, _) = e76.args
2458             self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
2459
2460         # "primaryGroupID" does not change if account type remains the same
2461
2462         # For a user account
2463
2464         ldb.add({
2465             "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
2466             "objectclass": "user",
2467             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)})
2468
2469         res1 = ldb.search("cn=ldaptestuser2,cn=users," + self.base_dn,
2470                           scope=SCOPE_BASE,
2471                           attrs=["userAccountControl"])
2472         self.assertTrue(len(res1) == 1)
2473         self.assertEquals(int(res1[0]["userAccountControl"][0]),
2474                           UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
2475
2476         m = Message()
2477         m.dn = Dn(ldb, "<SID=" + ldb.get_domain_sid() + "-" + str(DOMAIN_RID_ADMINS) + ">")
2478         m["member"] = MessageElement(
2479             "cn=ldaptestuser2,cn=users," + self.base_dn, FLAG_MOD_ADD, "member")
2480         ldb.modify(m)
2481
2482         m = Message()
2483         m.dn = Dn(ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2484         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_ADMINS),
2485                                              FLAG_MOD_REPLACE, "primaryGroupID")
2486         ldb.modify(m)
2487
2488         m = Message()
2489         m.dn = Dn(ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2490         m["userAccountControl"] = MessageElement(
2491             str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2492             FLAG_MOD_REPLACE, "userAccountControl")
2493         ldb.modify(m)
2494
2495         res1 = ldb.search("cn=ldaptestuser2,cn=users," + self.base_dn,
2496                           scope=SCOPE_BASE,
2497                           attrs=["userAccountControl", "primaryGroupID"])
2498         self.assertTrue(len(res1) == 1)
2499         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
2500         self.assertEquals(int(res1[0]["primaryGroupID"][0]), DOMAIN_RID_ADMINS)
2501
2502         # For a workstation account
2503
2504         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2505                           scope=SCOPE_BASE,
2506                           attrs=["primaryGroupID"])
2507         self.assertTrue(len(res1) == 1)
2508         self.assertEquals(int(res1[0]["primaryGroupID"][0]), DOMAIN_RID_DOMAIN_MEMBERS)
2509
2510         m = Message()
2511         m.dn = Dn(ldb, "<SID=" + ldb.get_domain_sid() + "-" + str(DOMAIN_RID_USERS) + ">")
2512         m["member"] = MessageElement(
2513             "cn=ldaptestcomputer,cn=computers," + self.base_dn, FLAG_MOD_ADD, "member")
2514         ldb.modify(m)
2515
2516         m = Message()
2517         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2518         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_USERS),
2519                                              FLAG_MOD_REPLACE, "primaryGroupID")
2520         ldb.modify(m)
2521
2522         m = Message()
2523         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2524         m["userAccountControl"] = MessageElement(
2525             str(UF_WORKSTATION_TRUST_ACCOUNT),
2526             FLAG_MOD_REPLACE, "userAccountControl")
2527         ldb.modify(m)
2528
2529         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2530                           scope=SCOPE_BASE,
2531                           attrs=["primaryGroupID"])
2532         self.assertTrue(len(res1) == 1)
2533         self.assertEquals(int(res1[0]["primaryGroupID"][0]), DOMAIN_RID_USERS)
2534
2535         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2536         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2537         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2538
2539     def find_repl_meta_data(self, rpmd, attid):
2540         for i in range(0, rpmd.ctr.count):
2541             m = rpmd.ctr.array[i]
2542             if m.attid == attid:
2543                 return m
2544         return None
2545
2546     def test_smartcard_required1(self):
2547         """Test the UF_SMARTCARD_REQUIRED behaviour"""
2548         print("Testing UF_SMARTCARD_REQUIRED behaviour\n")
2549
2550         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2551
2552         ldb.add({
2553             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
2554             "objectclass": "user",
2555             "userAccountControl": str(UF_NORMAL_ACCOUNT),
2556             "unicodePwd": "\"thatsAcomplPASS2\"".encode('utf-16-le')
2557         })
2558
2559         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2560                          scope=SCOPE_BASE,
2561                          attrs=["sAMAccountType", "userAccountControl",
2562                                 "pwdLastSet", "msDS-KeyVersionNumber",
2563                                 "replPropertyMetaData"])
2564         self.assertTrue(len(res) == 1)
2565         self.assertEqual(int(res[0]["sAMAccountType"][0]),
2566                          ATYPE_NORMAL_ACCOUNT)
2567         self.assertEqual(int(res[0]["userAccountControl"][0]),
2568                          UF_NORMAL_ACCOUNT)
2569         self.assertNotEqual(int(res[0]["pwdLastSet"][0]), 0)
2570         lastset = int(res[0]["pwdLastSet"][0])
2571         self.assertEqual(int(res[0]["msDS-KeyVersionNumber"][0]), 1)
2572         self.assertTrue(len(res[0]["replPropertyMetaData"]) == 1)
2573         rpmd = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
2574                           res[0]["replPropertyMetaData"][0])
2575         lastsetmd = self.find_repl_meta_data(rpmd,
2576                                              drsuapi.DRSUAPI_ATTID_pwdLastSet)
2577         self.assertIsNotNone(lastsetmd)
2578         self.assertEqual(lastsetmd.version, 1)
2579         nthashmd = self.find_repl_meta_data(rpmd,
2580                                             drsuapi.DRSUAPI_ATTID_unicodePwd)
2581         self.assertIsNotNone(nthashmd)
2582         self.assertEqual(nthashmd.version, 1)
2583         nthistmd = self.find_repl_meta_data(rpmd,
2584                                             drsuapi.DRSUAPI_ATTID_ntPwdHistory)
2585         self.assertIsNotNone(nthistmd)
2586         self.assertEqual(nthistmd.version, 1)
2587         lmhashmd = self.find_repl_meta_data(rpmd,
2588                                             drsuapi.DRSUAPI_ATTID_dBCSPwd)
2589         self.assertIsNotNone(lmhashmd)
2590         self.assertEqual(lmhashmd.version, 1)
2591         lmhistmd = self.find_repl_meta_data(rpmd,
2592                                             drsuapi.DRSUAPI_ATTID_lmPwdHistory)
2593         self.assertIsNotNone(lmhistmd)
2594         self.assertEqual(lmhistmd.version, 1)
2595         spcbmd = self.find_repl_meta_data(rpmd,
2596                                           drsuapi.DRSUAPI_ATTID_supplementalCredentials)
2597         self.assertIsNotNone(spcbmd)
2598         self.assertEqual(spcbmd.version, 1)
2599
2600         m = Message()
2601         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2602         m["userAccountControl"] = MessageElement(
2603             str(UF_NORMAL_ACCOUNT |UF_SMARTCARD_REQUIRED),
2604             FLAG_MOD_REPLACE, "userAccountControl")
2605         ldb.modify(m)
2606
2607         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2608                          scope=SCOPE_BASE,
2609                          attrs=["sAMAccountType", "userAccountControl",
2610                                 "pwdLastSet", "msDS-KeyVersionNumber",
2611                                 "replPropertyMetaData"])
2612         self.assertTrue(len(res) == 1)
2613         self.assertEqual(int(res[0]["sAMAccountType"][0]),
2614                          ATYPE_NORMAL_ACCOUNT)
2615         self.assertEqual(int(res[0]["userAccountControl"][0]),
2616                          UF_NORMAL_ACCOUNT |UF_SMARTCARD_REQUIRED)
2617         self.assertEqual(int(res[0]["pwdLastSet"][0]), lastset)
2618         lastset1 = int(res[0]["pwdLastSet"][0])
2619         self.assertEqual(int(res[0]["msDS-KeyVersionNumber"][0]), 2)
2620         self.assertTrue(len(res[0]["replPropertyMetaData"]) == 1)
2621         rpmd = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
2622                           res[0]["replPropertyMetaData"][0])
2623         lastsetmd = self.find_repl_meta_data(rpmd,
2624                                              drsuapi.DRSUAPI_ATTID_pwdLastSet)
2625         self.assertIsNotNone(lastsetmd)
2626         self.assertEqual(lastsetmd.version, 1)
2627         nthashmd = self.find_repl_meta_data(rpmd,
2628                                             drsuapi.DRSUAPI_ATTID_unicodePwd)
2629         self.assertIsNotNone(nthashmd)
2630         self.assertEqual(nthashmd.version, 2)
2631         nthistmd = self.find_repl_meta_data(rpmd,
2632                                             drsuapi.DRSUAPI_ATTID_ntPwdHistory)
2633         self.assertIsNotNone(nthistmd)
2634         self.assertEqual(nthistmd.version, 2)
2635         lmhashmd = self.find_repl_meta_data(rpmd,
2636                                             drsuapi.DRSUAPI_ATTID_dBCSPwd)
2637         self.assertIsNotNone(lmhashmd)
2638         self.assertEqual(lmhashmd.version, 2)
2639         lmhistmd = self.find_repl_meta_data(rpmd,
2640                                             drsuapi.DRSUAPI_ATTID_lmPwdHistory)
2641         self.assertIsNotNone(lmhistmd)
2642         self.assertEqual(lmhistmd.version, 2)
2643         spcbmd = self.find_repl_meta_data(rpmd,
2644                                           drsuapi.DRSUAPI_ATTID_supplementalCredentials)
2645         self.assertIsNotNone(spcbmd)
2646         self.assertEqual(spcbmd.version, 2)
2647
2648         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2649
2650     def test_smartcard_required2(self):
2651         """Test the UF_SMARTCARD_REQUIRED behaviour"""
2652         print("Testing UF_SMARTCARD_REQUIRED behaviour\n")
2653
2654         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2655
2656         ldb.add({
2657             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
2658             "objectclass": "user",
2659             "userAccountControl": str(UF_NORMAL_ACCOUNT |UF_ACCOUNTDISABLE),
2660         })
2661
2662         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2663                          scope=SCOPE_BASE,
2664                          attrs=["sAMAccountType", "userAccountControl",
2665                                 "pwdLastSet", "msDS-KeyVersionNumber",
2666                                 "replPropertyMetaData"])
2667         self.assertTrue(len(res) == 1)
2668         self.assertEqual(int(res[0]["sAMAccountType"][0]),
2669                          ATYPE_NORMAL_ACCOUNT)
2670         self.assertEqual(int(res[0]["userAccountControl"][0]),
2671                          UF_NORMAL_ACCOUNT |UF_ACCOUNTDISABLE)
2672         self.assertEqual(int(res[0]["pwdLastSet"][0]), 0)
2673         self.assertTrue("msDS-KeyVersionNumber" in res[0])
2674         self.assertEqual(int(res[0]["msDS-KeyVersionNumber"][0]), 1)
2675         self.assertTrue(len(res[0]["replPropertyMetaData"]) == 1)
2676         rpmd = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
2677                           res[0]["replPropertyMetaData"][0])
2678         lastsetmd = self.find_repl_meta_data(rpmd,
2679                                              drsuapi.DRSUAPI_ATTID_pwdLastSet)
2680         self.assertIsNotNone(lastsetmd)
2681         self.assertEqual(lastsetmd.version, 1)
2682         nthashmd = self.find_repl_meta_data(rpmd,
2683                                             drsuapi.DRSUAPI_ATTID_unicodePwd)
2684         self.assertIsNotNone(nthashmd)
2685         self.assertEqual(nthashmd.version, 1)
2686         nthistmd = self.find_repl_meta_data(rpmd,
2687                                             drsuapi.DRSUAPI_ATTID_ntPwdHistory)
2688         self.assertIsNotNone(nthistmd)
2689         self.assertEqual(nthistmd.version, 1)
2690         lmhashmd = self.find_repl_meta_data(rpmd,
2691                                             drsuapi.DRSUAPI_ATTID_dBCSPwd)
2692         self.assertIsNotNone(lmhashmd)
2693         self.assertEqual(lmhashmd.version, 1)
2694         lmhistmd = self.find_repl_meta_data(rpmd,
2695                                             drsuapi.DRSUAPI_ATTID_lmPwdHistory)
2696         self.assertIsNotNone(lmhistmd)
2697         self.assertEqual(lmhistmd.version, 1)
2698         spcbmd = self.find_repl_meta_data(rpmd,
2699                                           drsuapi.DRSUAPI_ATTID_supplementalCredentials)
2700         self.assertIsNone(spcbmd)
2701
2702         m = Message()
2703         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2704         m["userAccountControl"] = MessageElement(
2705             str(UF_NORMAL_ACCOUNT |UF_ACCOUNTDISABLE |UF_SMARTCARD_REQUIRED),
2706             FLAG_MOD_REPLACE, "userAccountControl")
2707         ldb.modify(m)
2708
2709         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2710                          scope=SCOPE_BASE,
2711                          attrs=["sAMAccountType", "userAccountControl",
2712                                 "pwdLastSet", "msDS-KeyVersionNumber",
2713                                 "replPropertyMetaData"])
2714         self.assertTrue(len(res) == 1)
2715         self.assertEqual(int(res[0]["sAMAccountType"][0]),
2716                          ATYPE_NORMAL_ACCOUNT)
2717         self.assertEqual(int(res[0]["userAccountControl"][0]),
2718                          UF_NORMAL_ACCOUNT |UF_ACCOUNTDISABLE |UF_SMARTCARD_REQUIRED)
2719         self.assertEqual(int(res[0]["pwdLastSet"][0]), 0)
2720         self.assertEqual(int(res[0]["msDS-KeyVersionNumber"][0]), 2)
2721         self.assertTrue(len(res[0]["replPropertyMetaData"]) == 1)
2722         rpmd = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
2723                           res[0]["replPropertyMetaData"][0])
2724         lastsetmd = self.find_repl_meta_data(rpmd,
2725                                              drsuapi.DRSUAPI_ATTID_pwdLastSet)
2726         self.assertIsNotNone(lastsetmd)
2727         self.assertEqual(lastsetmd.version, 1)
2728         nthashmd = self.find_repl_meta_data(rpmd,
2729                                             drsuapi.DRSUAPI_ATTID_unicodePwd)
2730         self.assertIsNotNone(nthashmd)
2731         self.assertEqual(nthashmd.version, 2)
2732         nthistmd = self.find_repl_meta_data(rpmd,
2733                                             drsuapi.DRSUAPI_ATTID_ntPwdHistory)
2734         self.assertIsNotNone(nthistmd)
2735         self.assertEqual(nthistmd.version, 2)
2736         lmhashmd = self.find_repl_meta_data(rpmd,
2737                                             drsuapi.DRSUAPI_ATTID_dBCSPwd)
2738         self.assertIsNotNone(lmhashmd)
2739         self.assertEqual(lmhashmd.version, 2)
2740         lmhistmd = self.find_repl_meta_data(rpmd,
2741                                             drsuapi.DRSUAPI_ATTID_lmPwdHistory)
2742         self.assertIsNotNone(lmhistmd)
2743         self.assertEqual(lmhistmd.version, 2)
2744         spcbmd = self.find_repl_meta_data(rpmd,
2745                                           drsuapi.DRSUAPI_ATTID_supplementalCredentials)
2746         self.assertIsNotNone(spcbmd)
2747         self.assertEqual(spcbmd.version, 1)
2748
2749         m = Message()
2750         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2751         m["userAccountControl"] = MessageElement(
2752             str(UF_NORMAL_ACCOUNT |UF_SMARTCARD_REQUIRED),
2753             FLAG_MOD_REPLACE, "userAccountControl")
2754         ldb.modify(m)
2755
2756         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2757                          scope=SCOPE_BASE,
2758                          attrs=["sAMAccountType", "userAccountControl",
2759                                 "pwdLastSet", "msDS-KeyVersionNumber",
2760                                 "replPropertyMetaData"])
2761         self.assertTrue(len(res) == 1)
2762         self.assertEqual(int(res[0]["sAMAccountType"][0]),
2763                          ATYPE_NORMAL_ACCOUNT)
2764         self.assertEqual(int(res[0]["userAccountControl"][0]),
2765                          UF_NORMAL_ACCOUNT |UF_SMARTCARD_REQUIRED)
2766         self.assertEqual(int(res[0]["pwdLastSet"][0]), 0)
2767         self.assertEqual(int(res[0]["msDS-KeyVersionNumber"][0]), 2)
2768         self.assertTrue(len(res[0]["replPropertyMetaData"]) == 1)
2769         rpmd = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
2770                           res[0]["replPropertyMetaData"][0])
2771         lastsetmd = self.find_repl_meta_data(rpmd,
2772                                              drsuapi.DRSUAPI_ATTID_pwdLastSet)
2773         self.assertIsNotNone(lastsetmd)
2774         self.assertEqual(lastsetmd.version, 1)
2775         nthashmd = self.find_repl_meta_data(rpmd,
2776                                             drsuapi.DRSUAPI_ATTID_unicodePwd)
2777         self.assertIsNotNone(nthashmd)
2778         self.assertEqual(nthashmd.version, 2)
2779         nthistmd = self.find_repl_meta_data(rpmd,
2780                                             drsuapi.DRSUAPI_ATTID_ntPwdHistory)
2781         self.assertIsNotNone(nthistmd)
2782         self.assertEqual(nthistmd.version, 2)
2783         lmhashmd = self.find_repl_meta_data(rpmd,
2784                                             drsuapi.DRSUAPI_ATTID_dBCSPwd)
2785         self.assertIsNotNone(lmhashmd)
2786         self.assertEqual(lmhashmd.version, 2)
2787         lmhistmd = self.find_repl_meta_data(rpmd,
2788                                             drsuapi.DRSUAPI_ATTID_lmPwdHistory)
2789         self.assertIsNotNone(lmhistmd)
2790         self.assertEqual(lmhistmd.version, 2)
2791         spcbmd = self.find_repl_meta_data(rpmd,
2792                                           drsuapi.DRSUAPI_ATTID_supplementalCredentials)
2793         self.assertIsNotNone(spcbmd)
2794         self.assertEqual(spcbmd.version, 1)
2795
2796         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2797
2798     def test_smartcard_required3(self):
2799         """Test the UF_SMARTCARD_REQUIRED behaviour"""
2800         print("Testing UF_SMARTCARD_REQUIRED behaviour\n")
2801
2802         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2803
2804         ldb.add({
2805             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
2806             "objectclass": "user",
2807             "userAccountControl": str(UF_NORMAL_ACCOUNT |UF_SMARTCARD_REQUIRED |UF_ACCOUNTDISABLE),
2808         })
2809
2810         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2811                          scope=SCOPE_BASE,
2812                          attrs=["sAMAccountType", "userAccountControl",
2813                                 "pwdLastSet", "msDS-KeyVersionNumber",
2814                                 "replPropertyMetaData"])
2815         self.assertTrue(len(res) == 1)
2816         self.assertEqual(int(res[0]["sAMAccountType"][0]),
2817                          ATYPE_NORMAL_ACCOUNT)
2818         self.assertEqual(int(res[0]["userAccountControl"][0]),
2819                          UF_NORMAL_ACCOUNT |UF_SMARTCARD_REQUIRED |UF_ACCOUNTDISABLE)
2820         self.assertEqual(int(res[0]["pwdLastSet"][0]), 0)
2821         self.assertEqual(int(res[0]["msDS-KeyVersionNumber"][0]), 1)
2822         self.assertTrue(len(res[0]["replPropertyMetaData"]) == 1)
2823         rpmd = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
2824                           res[0]["replPropertyMetaData"][0])
2825         lastsetmd = self.find_repl_meta_data(rpmd,
2826                                              drsuapi.DRSUAPI_ATTID_pwdLastSet)
2827         self.assertIsNotNone(lastsetmd)
2828         self.assertEqual(lastsetmd.version, 1)
2829         nthashmd = self.find_repl_meta_data(rpmd,
2830                                             drsuapi.DRSUAPI_ATTID_unicodePwd)
2831         self.assertIsNotNone(nthashmd)
2832         self.assertEqual(nthashmd.version, 1)
2833         nthistmd = self.find_repl_meta_data(rpmd,
2834                                             drsuapi.DRSUAPI_ATTID_ntPwdHistory)
2835         self.assertIsNotNone(nthistmd)
2836         self.assertEqual(nthistmd.version, 1)
2837         lmhashmd = self.find_repl_meta_data(rpmd,
2838                                             drsuapi.DRSUAPI_ATTID_dBCSPwd)
2839         self.assertIsNotNone(lmhashmd)
2840         self.assertEqual(lmhashmd.version, 1)
2841         lmhistmd = self.find_repl_meta_data(rpmd,
2842                                             drsuapi.DRSUAPI_ATTID_lmPwdHistory)
2843         self.assertIsNotNone(lmhistmd)
2844         self.assertEqual(lmhistmd.version, 1)
2845         spcbmd = self.find_repl_meta_data(rpmd,
2846                                           drsuapi.DRSUAPI_ATTID_supplementalCredentials)
2847         self.assertIsNotNone(spcbmd)
2848         self.assertEqual(spcbmd.version, 1)
2849
2850         m = Message()
2851         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2852         m["userAccountControl"] = MessageElement(
2853             str(UF_NORMAL_ACCOUNT |UF_SMARTCARD_REQUIRED),
2854             FLAG_MOD_REPLACE, "userAccountControl")
2855         ldb.modify(m)
2856
2857         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
2858                          scope=SCOPE_BASE,
2859                          attrs=["sAMAccountType", "userAccountControl",
2860                                 "pwdLastSet", "msDS-KeyVersionNumber",
2861                                 "replPropertyMetaData"])
2862         self.assertTrue(len(res) == 1)
2863         self.assertEqual(int(res[0]["sAMAccountType"][0]),
2864                          ATYPE_NORMAL_ACCOUNT)
2865         self.assertEqual(int(res[0]["userAccountControl"][0]),
2866                          UF_NORMAL_ACCOUNT |UF_SMARTCARD_REQUIRED)
2867         self.assertEqual(int(res[0]["pwdLastSet"][0]), 0)
2868         self.assertEqual(int(res[0]["msDS-KeyVersionNumber"][0]), 1)
2869         self.assertTrue(len(res[0]["replPropertyMetaData"]) == 1)
2870         rpmd = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
2871                           res[0]["replPropertyMetaData"][0])
2872         lastsetmd = self.find_repl_meta_data(rpmd,
2873                                              drsuapi.DRSUAPI_ATTID_pwdLastSet)
2874         self.assertIsNotNone(lastsetmd)
2875         self.assertEqual(lastsetmd.version, 1)
2876         nthashmd = self.find_repl_meta_data(rpmd,
2877                                             drsuapi.DRSUAPI_ATTID_unicodePwd)
2878         self.assertIsNotNone(nthashmd)
2879         self.assertEqual(nthashmd.version, 1)
2880         nthistmd = self.find_repl_meta_data(rpmd,
2881                                             drsuapi.DRSUAPI_ATTID_ntPwdHistory)
2882         self.assertIsNotNone(nthistmd)
2883         self.assertEqual(nthistmd.version, 1)
2884         lmhashmd = self.find_repl_meta_data(rpmd,
2885                                             drsuapi.DRSUAPI_ATTID_dBCSPwd)
2886         self.assertIsNotNone(lmhashmd)
2887         self.assertEqual(lmhashmd.version, 1)
2888         lmhistmd = self.find_repl_meta_data(rpmd,
2889                                             drsuapi.DRSUAPI_ATTID_lmPwdHistory)
2890         self.assertIsNotNone(lmhistmd)
2891         self.assertEqual(lmhistmd.version, 1)
2892         spcbmd = self.find_repl_meta_data(rpmd,
2893                                           drsuapi.DRSUAPI_ATTID_supplementalCredentials)
2894         self.assertIsNotNone(spcbmd)
2895         self.assertEqual(spcbmd.version, 1)
2896
2897         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2898
2899     def test_isCriticalSystemObject(self):
2900         """Test the isCriticalSystemObject behaviour"""
2901         print("Testing isCriticalSystemObject behaviour\n")
2902
2903         # Add tests
2904
2905         ldb.add({
2906             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2907             "objectclass": "computer"})
2908
2909         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2910                           scope=SCOPE_BASE,
2911                           attrs=["isCriticalSystemObject"])
2912         self.assertTrue(len(res1) == 1)
2913         self.assertTrue("isCriticalSystemObject" not in res1[0])
2914
2915         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2916
2917         ldb.add({
2918             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2919             "objectclass": "computer",
2920             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
2921
2922         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2923                           scope=SCOPE_BASE,
2924                           attrs=["isCriticalSystemObject"])
2925         self.assertTrue(len(res1) == 1)
2926         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "FALSE")
2927
2928         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2929
2930         ldb.add({
2931             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2932             "objectclass": "computer",
2933             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)})
2934
2935         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2936                           scope=SCOPE_BASE,
2937                           attrs=["isCriticalSystemObject"])
2938         self.assertTrue(len(res1) == 1)
2939         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2940
2941         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2942
2943         ldb.add({
2944             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2945             "objectclass": "computer",
2946             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
2947
2948         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2949                           scope=SCOPE_BASE,
2950                           attrs=["isCriticalSystemObject"])
2951         self.assertTrue(len(res1) == 1)
2952         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2953
2954         # Modification tests
2955
2956         m = Message()
2957         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2958         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2959                                                  FLAG_MOD_REPLACE, "userAccountControl")
2960         ldb.modify(m)
2961
2962         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2963                           scope=SCOPE_BASE,
2964                           attrs=["isCriticalSystemObject"])
2965         self.assertTrue(len(res1) == 1)
2966         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2967
2968         m = Message()
2969         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2970         m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT),
2971                                                  FLAG_MOD_REPLACE, "userAccountControl")
2972         ldb.modify(m)
2973
2974         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2975                           scope=SCOPE_BASE,
2976                           attrs=["isCriticalSystemObject"])
2977         self.assertTrue(len(res1) == 1)
2978         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "FALSE")
2979
2980         m = Message()
2981         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2982         m["userAccountControl"] = MessageElement(
2983             str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT),
2984             FLAG_MOD_REPLACE, "userAccountControl")
2985         ldb.modify(m)
2986
2987         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2988                           scope=SCOPE_BASE,
2989                           attrs=["isCriticalSystemObject"])
2990         self.assertTrue(len(res1) == 1)
2991         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2992
2993         m = Message()
2994         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2995         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2996                                                  FLAG_MOD_REPLACE, "userAccountControl")
2997         ldb.modify(m)
2998
2999         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3000                           scope=SCOPE_BASE,
3001                           attrs=["isCriticalSystemObject"])
3002         self.assertTrue(len(res1) == 1)
3003         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
3004
3005         m = Message()
3006         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3007         m["userAccountControl"] = MessageElement(str(UF_SERVER_TRUST_ACCOUNT),
3008                                                  FLAG_MOD_REPLACE, "userAccountControl")
3009         ldb.modify(m)
3010
3011         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3012                           scope=SCOPE_BASE,
3013                           attrs=["isCriticalSystemObject"])
3014         self.assertTrue(len(res1) == 1)
3015         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
3016
3017         m = Message()
3018         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3019         m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT),
3020                                                  FLAG_MOD_REPLACE, "userAccountControl")
3021         ldb.modify(m)
3022
3023         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3024                           scope=SCOPE_BASE,
3025                           attrs=["isCriticalSystemObject"])
3026         self.assertTrue(len(res1) == 1)
3027         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "FALSE")
3028
3029         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3030
3031     def test_service_principal_name_updates(self):
3032         """Test the servicePrincipalNames update behaviour"""
3033         print("Testing servicePrincipalNames update behaviour\n")
3034
3035         ldb.add({
3036             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
3037             "objectclass": "computer",
3038             "dNSHostName": "testname.testdom"})
3039
3040         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3041                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3042         self.assertTrue(len(res) == 1)
3043         self.assertFalse("servicePrincipalName" in res[0])
3044
3045         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3046
3047         ldb.add({
3048             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
3049             "objectclass": "computer",
3050             "servicePrincipalName": "HOST/testname.testdom"})
3051
3052         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3053                          scope=SCOPE_BASE, attrs=["dNSHostName"])
3054         self.assertTrue(len(res) == 1)
3055         self.assertFalse("dNSHostName" in res[0])
3056
3057         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3058
3059         ldb.add({
3060             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
3061             "objectclass": "computer",
3062             "dNSHostName": "testname2.testdom",
3063             "servicePrincipalName": "HOST/testname.testdom"})
3064
3065         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3066                          scope=SCOPE_BASE, attrs=["dNSHostName"])
3067         self.assertTrue(len(res) == 1)
3068         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
3069
3070         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3071                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3072         self.assertTrue(len(res) == 1)
3073         self.assertEquals(res[0]["servicePrincipalName"][0],
3074                           "HOST/testname.testdom")
3075
3076         m = Message()
3077         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3078         m["dNSHostName"] = MessageElement("testname.testdoM",
3079                                           FLAG_MOD_REPLACE, "dNSHostName")
3080         ldb.modify(m)
3081
3082         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3083                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3084         self.assertTrue(len(res) == 1)
3085         self.assertEquals(res[0]["servicePrincipalName"][0],
3086                           "HOST/testname.testdom")
3087
3088         m = Message()
3089         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3090         m["dNSHostName"] = MessageElement("testname2.testdom2",
3091                                           FLAG_MOD_REPLACE, "dNSHostName")
3092         ldb.modify(m)
3093
3094         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3095                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3096         self.assertTrue(len(res) == 1)
3097         self.assertEquals(res[0]["servicePrincipalName"][0],
3098                           "HOST/testname2.testdom2")
3099
3100         m = Message()
3101         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3102         m["dNSHostName"] = MessageElement([],
3103                                           FLAG_MOD_DELETE, "dNSHostName")
3104         ldb.modify(m)
3105
3106         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3107                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3108         self.assertTrue(len(res) == 1)
3109         self.assertEquals(res[0]["servicePrincipalName"][0],
3110                           "HOST/testname2.testdom2")
3111
3112         m = Message()
3113         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3114         m["dNSHostName"] = MessageElement("testname.testdom3",
3115                                           FLAG_MOD_REPLACE, "dNSHostName")
3116         ldb.modify(m)
3117
3118         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3119                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3120         self.assertTrue(len(res) == 1)
3121         self.assertEquals(res[0]["servicePrincipalName"][0],
3122                           "HOST/testname2.testdom2")
3123
3124         m = Message()
3125         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3126         m["dNSHostName"] = MessageElement("testname2.testdom2",
3127                                           FLAG_MOD_REPLACE, "dNSHostName")
3128         ldb.modify(m)
3129
3130         m = Message()
3131         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3132         m["dNSHostName"] = MessageElement("testname3.testdom3",
3133                                           FLAG_MOD_REPLACE, "dNSHostName")
3134         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom2",
3135                                                    FLAG_MOD_REPLACE,
3136                                                    "servicePrincipalName")
3137         ldb.modify(m)
3138
3139         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3140                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3141         self.assertTrue(len(res) == 1)
3142         self.assertEquals(res[0]["servicePrincipalName"][0],
3143                           "HOST/testname3.testdom3")
3144
3145         m = Message()
3146         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3147         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom2",
3148                                                    FLAG_MOD_REPLACE,
3149                                                    "servicePrincipalName")
3150         m["dNSHostName"] = MessageElement("testname4.testdom4",
3151                                           FLAG_MOD_REPLACE, "dNSHostName")
3152         ldb.modify(m)
3153
3154         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3155                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3156         self.assertTrue(len(res) == 1)
3157         self.assertEquals(res[0]["servicePrincipalName"][0],
3158                           "HOST/testname2.testdom2")
3159
3160         m = Message()
3161         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3162         m["servicePrincipalName"] = MessageElement([],
3163                                                    FLAG_MOD_DELETE,
3164                                                    "servicePrincipalName")
3165         ldb.modify(m)
3166
3167         m = Message()
3168         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3169         m["dNSHostName"] = MessageElement("testname2.testdom2",
3170                                           FLAG_MOD_REPLACE, "dNSHostName")
3171         ldb.modify(m)
3172
3173         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3174                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3175         self.assertTrue(len(res) == 1)
3176         self.assertFalse("servicePrincipalName" in res[0])
3177
3178         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3179
3180         ldb.add({
3181             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
3182             "objectclass": "computer",
3183             "sAMAccountName": "testname$"})
3184
3185         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3186                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3187         self.assertTrue(len(res) == 1)
3188         self.assertFalse("servicePrincipalName" in res[0])
3189
3190         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3191
3192         ldb.add({
3193             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
3194             "objectclass": "computer",
3195             "servicePrincipalName": "HOST/testname"})
3196
3197         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3198                          scope=SCOPE_BASE, attrs=["sAMAccountName"])
3199         self.assertTrue(len(res) == 1)
3200         self.assertTrue("sAMAccountName" in res[0])
3201
3202         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3203
3204         ldb.add({
3205             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
3206             "objectclass": "computer",
3207             "sAMAccountName": "testname$",
3208             "servicePrincipalName": "HOST/testname"})
3209
3210         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3211                          scope=SCOPE_BASE, attrs=["sAMAccountName"])
3212         self.assertTrue(len(res) == 1)
3213         self.assertEquals(res[0]["sAMAccountName"][0], "testname$")
3214
3215         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3216                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3217         self.assertTrue(len(res) == 1)
3218         self.assertEquals(res[0]["servicePrincipalName"][0],
3219                           "HOST/testname")
3220
3221         m = Message()
3222         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3223         m["sAMAccountName"] = MessageElement("testnamE$",
3224                                              FLAG_MOD_REPLACE, "sAMAccountName")
3225         ldb.modify(m)
3226
3227         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3228                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3229         self.assertTrue(len(res) == 1)
3230         self.assertEquals(res[0]["servicePrincipalName"][0],
3231                           "HOST/testname")
3232
3233         m = Message()
3234         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3235         m["sAMAccountName"] = MessageElement("testname",
3236                                              FLAG_MOD_REPLACE, "sAMAccountName")
3237         ldb.modify(m)
3238
3239         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3240                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3241         self.assertTrue(len(res) == 1)
3242         self.assertEquals(res[0]["servicePrincipalName"][0],
3243                           "HOST/testname")
3244
3245         m = Message()
3246         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3247         m["sAMAccountName"] = MessageElement("test$name$",
3248                                              FLAG_MOD_REPLACE, "sAMAccountName")
3249         ldb.modify(m)
3250
3251         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3252                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3253         self.assertTrue(len(res) == 1)
3254         self.assertEquals(res[0]["servicePrincipalName"][0],
3255                           "HOST/test$name")
3256
3257         m = Message()
3258         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3259         m["sAMAccountName"] = MessageElement("testname2",
3260                                              FLAG_MOD_REPLACE, "sAMAccountName")
3261         ldb.modify(m)
3262
3263         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3264                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3265         self.assertTrue(len(res) == 1)
3266         self.assertEquals(res[0]["servicePrincipalName"][0],
3267                           "HOST/testname2")
3268
3269         m = Message()
3270         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3271         m["sAMAccountName"] = MessageElement("testname3",
3272                                              FLAG_MOD_REPLACE, "sAMAccountName")
3273         m["servicePrincipalName"] = MessageElement("HOST/testname2",
3274                                                    FLAG_MOD_REPLACE,
3275                                                    "servicePrincipalName")
3276         ldb.modify(m)
3277
3278         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3279                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3280         self.assertTrue(len(res) == 1)
3281         self.assertEquals(res[0]["servicePrincipalName"][0],
3282                           "HOST/testname3")
3283
3284         m = Message()
3285         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3286         m["servicePrincipalName"] = MessageElement("HOST/testname2",
3287                                                    FLAG_MOD_REPLACE,
3288                                                    "servicePrincipalName")
3289         m["sAMAccountName"] = MessageElement("testname4",
3290                                              FLAG_MOD_REPLACE, "sAMAccountName")
3291         ldb.modify(m)
3292
3293         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3294                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3295         self.assertTrue(len(res) == 1)
3296         self.assertEquals(res[0]["servicePrincipalName"][0],
3297                           "HOST/testname2")
3298
3299         m = Message()
3300         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3301         m["servicePrincipalName"] = MessageElement([],
3302                                                    FLAG_MOD_DELETE,
3303                                                    "servicePrincipalName")
3304         ldb.modify(m)
3305
3306         m = Message()
3307         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3308         m["sAMAccountName"] = MessageElement("testname2",
3309                                              FLAG_MOD_REPLACE, "sAMAccountName")
3310         ldb.modify(m)
3311
3312         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3313                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
3314         self.assertTrue(len(res) == 1)
3315         self.assertFalse("servicePrincipalName" in res[0])
3316
3317         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3318
3319         ldb.add({
3320             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
3321             "objectclass": "computer",
3322             "dNSHostName": "testname.testdom",
3323             "sAMAccountName": "testname$",
3324             "servicePrincipalName": ["HOST/testname.testdom", "HOST/testname"]
3325         })
3326
3327         m = Message()
3328         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3329         m["dNSHostName"] = MessageElement("testname2.testdom",
3330                                           FLAG_MOD_REPLACE, "dNSHostName")
3331         m["sAMAccountName"] = MessageElement("testname2$",
3332                                              FLAG_MOD_REPLACE, "sAMAccountName")
3333         ldb.modify(m)
3334
3335         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3336                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
3337         self.assertTrue(len(res) == 1)
3338         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
3339         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
3340         self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2" or
3341                         res[0]["servicePrincipalName"][1] == "HOST/testname2")
3342         self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2.testdom" or
3343                         res[0]["servicePrincipalName"][1] == "HOST/testname2.testdom")
3344
3345         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3346
3347         ldb.add({
3348             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
3349             "objectclass": "computer",
3350             "dNSHostName": "testname.testdom",
3351             "sAMAccountName": "testname$",
3352             "servicePrincipalName": ["HOST/testname.testdom", "HOST/testname"]
3353         })
3354
3355         m = Message()
3356         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3357         m["sAMAccountName"] = MessageElement("testname2$",
3358                                              FLAG_MOD_REPLACE, "sAMAccountName")
3359         m["dNSHostName"] = MessageElement("testname2.testdom",
3360                                           FLAG_MOD_REPLACE, "dNSHostName")
3361         ldb.modify(m)
3362
3363         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3364                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
3365         self.assertTrue(len(res) == 1)
3366         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
3367         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
3368         self.assertTrue(len(res[0]["servicePrincipalName"]) == 2)
3369         self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"])
3370         self.assertTrue("HOST/testname2.testdom" in res[0]["servicePrincipalName"])
3371
3372         m = Message()
3373         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3374         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom",
3375                                                    FLAG_MOD_ADD, "servicePrincipalName")
3376         try:
3377             ldb.modify(m)
3378             self.fail()
3379         except LdbError as e77:
3380             (num, _) = e77.args
3381             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
3382
3383         m = Message()
3384         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3385         m["servicePrincipalName"] = MessageElement("HOST/testname3",
3386                                                    FLAG_MOD_ADD, "servicePrincipalName")
3387         ldb.modify(m)
3388
3389         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3390                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
3391         self.assertTrue(len(res) == 1)
3392         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
3393         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
3394         self.assertTrue(len(res[0]["servicePrincipalName"]) == 3)
3395         self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"])
3396         self.assertTrue("HOST/testname3" in res[0]["servicePrincipalName"])
3397         self.assertTrue("HOST/testname2.testdom" in res[0]["servicePrincipalName"])
3398
3399         m = Message()
3400         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3401         m["dNSHostName"] = MessageElement("testname3.testdom",
3402                                           FLAG_MOD_REPLACE, "dNSHostName")
3403         m["servicePrincipalName"] = MessageElement("HOST/testname3.testdom",
3404                                                    FLAG_MOD_ADD, "servicePrincipalName")
3405         ldb.modify(m)
3406
3407         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
3408                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
3409         self.assertTrue(len(res) == 1)
3410         self.assertEquals(res[0]["dNSHostName"][0], "testname3.testdom")
3411         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
3412         self.assertTrue(len(res[0]["servicePrincipalName"]) == 3)
3413         self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"])
3414         self.assertTrue("HOST/testname3" in res[0]["servicePrincipalName"])
3415         self.assertTrue("HOST/testname3.testdom" in res[0]["servicePrincipalName"])
3416
3417         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
3418
3419     def test_sam_description_attribute(self):
3420         """Test SAM description attribute"""
3421         print("Test SAM description attribute")
3422
3423         self.ldb.add({
3424             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
3425             "objectclass": "group",
3426             "description": "desc1"
3427         })
3428
3429         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
3430                          scope=SCOPE_BASE, attrs=["description"])
3431         self.assertTrue(len(res) == 1)
3432         self.assertTrue("description" in res[0])
3433         self.assertTrue(len(res[0]["description"]) == 1)
3434         self.assertEquals(res[0]["description"][0], "desc1")
3435
3436         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3437
3438         self.ldb.add({
3439             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
3440             "objectclass": "group",
3441             "description": ["desc1", "desc2"]})
3442
3443         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
3444                          scope=SCOPE_BASE, attrs=["description"])
3445         self.assertTrue(len(res) == 1)
3446         self.assertTrue("description" in res[0])
3447         self.assertTrue(len(res[0]["description"]) == 2)
3448         self.assertTrue(res[0]["description"][0] == "desc1" or
3449                         res[0]["description"][1] == "desc1")
3450         self.assertTrue(res[0]["description"][0] == "desc2" or
3451                         res[0]["description"][1] == "desc2")
3452
3453         m = Message()
3454         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3455         m["description"] = MessageElement(["desc1", "desc2"], FLAG_MOD_REPLACE,
3456                                           "description")
3457         try:
3458             ldb.modify(m)
3459             self.fail()
3460         except LdbError as e78:
3461             (num, _) = e78.args
3462             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
3463
3464         m = Message()
3465         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3466         m["description"] = MessageElement(["desc1", "desc2"], FLAG_MOD_DELETE,
3467                                           "description")
3468         ldb.modify(m)
3469
3470         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3471
3472         self.ldb.add({
3473             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
3474             "objectclass": "group"})
3475
3476         m = Message()
3477         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3478         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
3479                                           "description")
3480         ldb.modify(m)
3481
3482         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
3483                          scope=SCOPE_BASE, attrs=["description"])
3484         self.assertTrue(len(res) == 1)
3485         self.assertTrue("description" in res[0])
3486         self.assertTrue(len(res[0]["description"]) == 1)
3487         self.assertEquals(res[0]["description"][0], "desc1")
3488
3489         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3490
3491         self.ldb.add({
3492             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
3493             "objectclass": "group",
3494             "description": ["desc1", "desc2"]})
3495
3496         m = Message()
3497         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3498         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
3499                                           "description")
3500         ldb.modify(m)
3501
3502         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
3503                          scope=SCOPE_BASE, attrs=["description"])
3504         self.assertTrue(len(res) == 1)
3505         self.assertTrue("description" in res[0])
3506         self.assertTrue(len(res[0]["description"]) == 1)
3507         self.assertEquals(res[0]["description"][0], "desc1")
3508
3509         m = Message()
3510         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3511         m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
3512                                           "description")
3513         try:
3514             ldb.modify(m)
3515             self.fail()
3516         except LdbError as e79:
3517             (num, _) = e79.args
3518             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
3519
3520         m = Message()
3521         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3522         m["description"] = MessageElement(["desc1", "desc2"], FLAG_MOD_DELETE,
3523                                           "description")
3524         try:
3525             ldb.modify(m)
3526             self.fail()
3527         except LdbError as e80:
3528             (num, _) = e80.args
3529             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
3530
3531         m = Message()
3532         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3533         m["description"] = MessageElement("desc1", FLAG_MOD_DELETE,
3534                                           "description")
3535         ldb.modify(m)
3536         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
3537                          scope=SCOPE_BASE, attrs=["description"])
3538         self.assertTrue(len(res) == 1)
3539         self.assertFalse("description" in res[0])
3540
3541         m = Message()
3542         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3543         m["description"] = MessageElement(["desc1", "desc2"], FLAG_MOD_REPLACE,
3544                                           "description")
3545         try:
3546             ldb.modify(m)
3547             self.fail()
3548         except LdbError as e81:
3549             (num, _) = e81.args
3550             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
3551
3552         m = Message()
3553         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3554         m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
3555                                           "description")
3556         try:
3557             ldb.modify(m)
3558             self.fail()
3559         except LdbError as e82:
3560             (num, _) = e82.args
3561             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
3562
3563         m = Message()
3564         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3565         m["description"] = MessageElement("desc1", FLAG_MOD_ADD,
3566                                           "description")
3567         ldb.modify(m)
3568
3569         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
3570                          scope=SCOPE_BASE, attrs=["description"])
3571         self.assertTrue(len(res) == 1)
3572         self.assertTrue("description" in res[0])
3573         self.assertTrue(len(res[0]["description"]) == 1)
3574         self.assertEquals(res[0]["description"][0], "desc1")
3575
3576         m = Message()
3577         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3578         m.add(MessageElement("desc1", FLAG_MOD_DELETE, "description"))
3579         m.add(MessageElement("desc2", FLAG_MOD_ADD, "description"))
3580         ldb.modify(m)
3581
3582         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
3583                          scope=SCOPE_BASE, attrs=["description"])
3584         self.assertTrue(len(res) == 1)
3585         self.assertTrue("description" in res[0])
3586         self.assertTrue(len(res[0]["description"]) == 1)
3587         self.assertEquals(res[0]["description"][0], "desc2")
3588
3589         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3590
3591     def test_fSMORoleOwner_attribute(self):
3592         """Test fSMORoleOwner attribute"""
3593         print("Test fSMORoleOwner attribute")
3594
3595         ds_service_name = self.ldb.get_dsServiceName()
3596
3597         # The "fSMORoleOwner" attribute can only be set to "nTDSDSA" entries,
3598         # invalid DNs return ERR_UNWILLING_TO_PERFORM
3599
3600         try:
3601             self.ldb.add({
3602                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
3603                 "objectclass": "group",
3604                 "fSMORoleOwner": self.base_dn})
3605             self.fail()
3606         except LdbError as e83:
3607             (num, _) = e83.args
3608             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
3609
3610         try:
3611             self.ldb.add({
3612                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
3613                 "objectclass": "group",
3614                 "fSMORoleOwner": []})
3615             self.fail()
3616         except LdbError as e84:
3617             (num, _) = e84.args
3618             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
3619
3620         # We are able to set it to a valid "nTDSDSA" entry if the server is
3621         # capable of handling the role
3622
3623         self.ldb.add({
3624             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
3625             "objectclass": "group",
3626             "fSMORoleOwner": ds_service_name})
3627
3628         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3629
3630         self.ldb.add({
3631             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
3632             "objectclass": "group"})
3633
3634         m = Message()
3635         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3636         m.add(MessageElement(self.base_dn, FLAG_MOD_REPLACE, "fSMORoleOwner"))
3637         try:
3638             ldb.modify(m)
3639             self.fail()
3640         except LdbError as e85:
3641             (num, _) = e85.args
3642             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
3643
3644         m = Message()
3645         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3646         m.add(MessageElement([], FLAG_MOD_REPLACE, "fSMORoleOwner"))
3647         try:
3648             ldb.modify(m)
3649             self.fail()
3650         except LdbError as e86:
3651             (num, _) = e86.args
3652             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
3653
3654         # We are able to set it to a valid "nTDSDSA" entry if the server is
3655         # capable of handling the role
3656
3657         m = Message()
3658         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3659         m.add(MessageElement(ds_service_name, FLAG_MOD_REPLACE, "fSMORoleOwner"))
3660         ldb.modify(m)
3661
3662         # A clean-out works on plain entries, not master (schema, PDC...) DNs
3663
3664         m = Message()
3665         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3666         m.add(MessageElement([], FLAG_MOD_DELETE, "fSMORoleOwner"))
3667         ldb.modify(m)
3668
3669         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
3670
3671     def test_protected_sid_objects(self):
3672         """Test deletion of objects with RID < 1000"""
3673         # a list of some well-known sids
3674         # objects in Builtin are aready covered by objectclass
3675         protected_list = [
3676             ["CN=Domain Admins", "CN=Users,"],
3677             ["CN=Schema Admins", "CN=Users,"],
3678             ["CN=Enterprise Admins", "CN=Users,"],
3679             ["CN=Administrator", "CN=Users,"],
3680             ["CN=Domain Controllers", "CN=Users,"],
3681         ]
3682
3683         for pr_object in protected_list:
3684             try:
3685                 self.ldb.delete(pr_object[0] + "," + pr_object[1] + self.base_dn)
3686             except LdbError as e7:
3687                 (num, _) = e7.args
3688                 self.assertEquals(num, ERR_OTHER)
3689             else:
3690                 self.fail("Deleted " + pr_object[0])
3691
3692             try:
3693                 self.ldb.rename(pr_object[0] + "," + pr_object[1] + self.base_dn,
3694                                 pr_object[0] + "2," + pr_object[1] + self.base_dn)
3695             except LdbError as e8:
3696                 (num, _) = e8.args
3697                 self.fail("Could not rename " + pr_object[0])
3698
3699             self.ldb.rename(pr_object[0] + "2," + pr_object[1] + self.base_dn,
3700                             pr_object[0] + "," + pr_object[1] + self.base_dn)
3701
3702     def test_new_user_default_attributes(self):
3703         """Test default attributes for new user objects"""
3704         print("Test default attributes for new User objects\n")
3705
3706         user_name = "ldaptestuser"
3707         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
3708         ldb.add({
3709             "dn": user_dn,
3710             "objectclass": "user",
3711             "sAMAccountName": user_name})
3712
3713         res = ldb.search(user_dn, scope=SCOPE_BASE)
3714         self.assertTrue(len(res) == 1)
3715         user_obj = res[0]
3716
3717         expected_attrs = {"primaryGroupID": MessageElement(["513"]),
3718                           "logonCount": MessageElement(["0"]),
3719                           "cn": MessageElement([user_name]),
3720                           "countryCode": MessageElement(["0"]),
3721                           "objectClass": MessageElement(["top", "person", "organizationalPerson", "user"]),
3722                           "instanceType": MessageElement(["4"]),
3723                           "distinguishedName": MessageElement([user_dn]),
3724                           "sAMAccountType": MessageElement(["805306368"]),
3725                           "objectSid": "**SKIP**",
3726                           "whenCreated": "**SKIP**",
3727                           "uSNCreated": "**SKIP**",
3728                           "badPasswordTime": MessageElement(["0"]),
3729                           "dn": Dn(ldb, user_dn),
3730                           "pwdLastSet": MessageElement(["0"]),
3731                           "sAMAccountName": MessageElement([user_name]),
3732                           "objectCategory": MessageElement(["CN=Person,%s" % ldb.get_schema_basedn().get_linearized()]),
3733                           "objectGUID": "**SKIP**",
3734                           "whenChanged": "**SKIP**",
3735                           "badPwdCount": MessageElement(["0"]),
3736                           "accountExpires": MessageElement(["9223372036854775807"]),
3737                           "name": MessageElement([user_name]),
3738                           "codePage": MessageElement(["0"]),
3739                           "userAccountControl": MessageElement(["546"]),
3740                           "lastLogon": MessageElement(["0"]),
3741                           "uSNChanged": "**SKIP**",
3742                           "lastLogoff": MessageElement(["0"])}
3743         # assert we have expected attribute names
3744         actual_names = set(user_obj.keys())
3745         # Samba does not use 'dSCorePropagationData', so skip it
3746         actual_names -= set(['dSCorePropagationData'])
3747         self.assertEqual(set(expected_attrs.keys()), actual_names, "Actual object does not have expected attributes")
3748         # check attribute values
3749         for name in expected_attrs.keys():
3750             actual_val = user_obj.get(name)
3751             self.assertFalse(actual_val is None, "No value for attribute '%s'" % name)
3752             expected_val = expected_attrs[name]
3753             if expected_val == "**SKIP**":
3754                 # "**ANY**" values means "any"
3755                 continue
3756             self.assertEqual(expected_val, actual_val,
3757                              "Unexpected value[%r] for '%s' expected[%r]" %
3758                              (actual_val, name, expected_val))
3759         # clean up
3760         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
3761
3762
3763 if not "://" in host:
3764     if os.path.isfile(host):
3765         host = "tdb://%s" % host
3766     else:
3767         host = "ldap://%s" % host
3768
3769 ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp)
3770
3771 TestProgram(module=__name__, opts=subunitopts)