s4:sam.py - "servicePrincipalName" - test for case-insensitiveness
[metze/samba/wip.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 import optparse
6 import sys
7 import os
8
9 sys.path.insert(0, "bin/python")
10 import samba
11 samba.ensure_external_module("testtools", "testtools")
12 samba.ensure_external_module("subunit", "subunit/python")
13
14 import samba.getopt as options
15
16 from samba.auth import system_session
17 from ldb import SCOPE_BASE, LdbError
18 from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
19 from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
20 from ldb import ERR_OTHER, ERR_NO_SUCH_ATTRIBUTE
21 from ldb import ERR_OBJECT_CLASS_VIOLATION
22 from ldb import ERR_CONSTRAINT_VIOLATION
23 from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
24 from ldb import Message, MessageElement, Dn
25 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
26 from samba.samdb import SamDB
27 from samba.dsdb import (UF_NORMAL_ACCOUNT, UF_ACCOUNTDISABLE,
28     UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT,
29     UF_PARTIAL_SECRETS_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT,
30     UF_PASSWD_NOTREQD, UF_LOCKOUT, UF_PASSWORD_EXPIRED, ATYPE_NORMAL_ACCOUNT,
31     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP, GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
32     GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP,
33     GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP, GTYPE_DISTRIBUTION_GLOBAL_GROUP,
34     GTYPE_DISTRIBUTION_UNIVERSAL_GROUP,
35     ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_UNIVERSAL_GROUP,
36     ATYPE_SECURITY_LOCAL_GROUP, ATYPE_DISTRIBUTION_GLOBAL_GROUP,
37     ATYPE_DISTRIBUTION_UNIVERSAL_GROUP, ATYPE_DISTRIBUTION_LOCAL_GROUP,
38     ATYPE_WORKSTATION_TRUST)
39 from samba.dcerpc.security import (DOMAIN_RID_USERS, DOMAIN_RID_ADMINS,
40     DOMAIN_RID_DOMAIN_MEMBERS, DOMAIN_RID_DCS, DOMAIN_RID_READONLY_DCS)
41
42 from subunit.run import SubunitTestRunner
43 import unittest
44
45 from samba.dcerpc import security
46 from samba.tests import delete_force
47
48 parser = optparse.OptionParser("sam.py [options] <host>")
49 sambaopts = options.SambaOptions(parser)
50 parser.add_option_group(sambaopts)
51 parser.add_option_group(options.VersionOptions(parser))
52 # use command line creds if available
53 credopts = options.CredentialsOptions(parser)
54 parser.add_option_group(credopts)
55 opts, args = parser.parse_args()
56
57 if len(args) < 1:
58     parser.print_usage()
59     sys.exit(1)
60
61 host = args[0]
62
63 lp = sambaopts.get_loadparm()
64 creds = credopts.get_credentials(lp)
65
66 class SamTests(samba.tests.TestCase):
67
68     def setUp(self):
69         super(SamTests, self).setUp()
70         self.ldb = ldb
71         self.base_dn = ldb.domain_dn()
72
73         print "baseDN: %s\n" % self.base_dn
74
75         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
76         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
77         delete_force(self.ldb, "cn=ldaptest\,specialuser,cn=users," + self.base_dn)
78         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
79         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
80         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
81
82     def test_users_groups(self):
83         """This tests the SAM users and groups behaviour"""
84         print "Testing users and groups behaviour\n"
85
86         ldb.add({
87             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
88             "objectclass": "group"})
89
90         ldb.add({
91             "dn": "cn=ldaptestgroup2,cn=users," + self.base_dn,
92             "objectclass": "group"})
93
94         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
95                           scope=SCOPE_BASE, attrs=["objectSID"])
96         self.assertTrue(len(res1) == 1)
97         group_rid_1 = security.dom_sid(ldb.schema_format_value("objectSID",
98           res1[0]["objectSID"][0])).split()[1]
99
100         res1 = ldb.search("cn=ldaptestgroup2,cn=users," + self.base_dn,
101                           scope=SCOPE_BASE, attrs=["objectSID"])
102         self.assertTrue(len(res1) == 1)
103         group_rid_2 = security.dom_sid(ldb.schema_format_value("objectSID",
104           res1[0]["objectSID"][0])).split()[1]
105
106         # Try to create a user with an invalid account name
107         try:
108             ldb.add({
109                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
110                 "objectclass": "user",
111                 "sAMAccountName": "administrator"})
112             self.fail()
113         except LdbError, (num, _):
114             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
115         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
116
117         # Try to create a user with an invalid account name
118         try:
119             ldb.add({
120                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
121                 "objectclass": "user",
122                 "sAMAccountName": []})
123             self.fail()
124         except LdbError, (num, _):
125             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
126         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
127
128         # Try to create a user with an invalid primary group
129         try:
130             ldb.add({
131                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
132                 "objectclass": "user",
133                 "primaryGroupID": "0"})
134             self.fail()
135         except LdbError, (num, _):
136             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
137         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
138
139         # Try to Create a user with a valid primary group
140         try:
141             ldb.add({
142                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
143                 "objectclass": "user",
144                 "primaryGroupID": str(group_rid_1)})
145             self.fail()
146         except LdbError, (num, _):
147             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
148         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
149
150         # Test to see how we should behave when the user account doesn't
151         # exist
152         m = Message()
153         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
154         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
155           "primaryGroupID")
156         try:
157             ldb.modify(m)
158             self.fail()
159         except LdbError, (num, _):
160             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
161
162         # Test to see how we should behave when the account isn't a user
163         m = Message()
164         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
165         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
166           "primaryGroupID")
167         try:
168             ldb.modify(m)
169             self.fail()
170         except LdbError, (num, _):
171             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
172
173         # Test default primary groups on add operations
174
175         ldb.add({
176             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
177             "objectclass": "user"})
178
179         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
180                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
181         self.assertTrue(len(res1) == 1)
182         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
183
184         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
185
186         ldb.add({
187             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
188             "objectclass": "user",
189             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD) })
190
191         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
192                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
193         self.assertTrue(len(res1) == 1)
194         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
195
196         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
197
198         # unfortunately the INTERDOMAIN_TRUST_ACCOUNT case cannot be tested
199         # since such accounts aren't directly creatable (ACCESS_DENIED)
200
201         ldb.add({
202             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
203             "objectclass": "computer",
204             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
205
206         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
207                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
208         self.assertTrue(len(res1) == 1)
209         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DOMAIN_MEMBERS))
210
211         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
212
213         ldb.add({
214             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
215             "objectclass": "computer",
216             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
217
218         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
219                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
220         self.assertTrue(len(res1) == 1)
221         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DCS))
222
223         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
224
225         # Read-only DC accounts are only creatable by
226         # UF_WORKSTATION_TRUST_ACCOUNT and work only on DCs >= 2008 (therefore
227         # we have a fallback in the assertion)
228         ldb.add({
229             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
230             "objectclass": "computer",
231             "userAccountControl": str(UF_PARTIAL_SECRETS_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
232
233         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
234                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
235         self.assertTrue(len(res1) == 1)
236         self.assertTrue(res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_READONLY_DCS) or
237                         res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_DOMAIN_MEMBERS))
238
239         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
240
241         # Test default primary groups on modify operations
242
243         ldb.add({
244             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
245             "objectclass": "user"})
246
247         m = Message()
248         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
249         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
250           "userAccountControl")
251         ldb.modify(m)
252
253         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
254                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
255         self.assertTrue(len(res1) == 1)
256         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
257
258         # unfortunately the INTERDOMAIN_TRUST_ACCOUNT case cannot be tested
259         # since such accounts aren't directly creatable (ACCESS_DENIED)
260
261         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
262
263         ldb.add({
264             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
265             "objectclass": "computer"})
266
267         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
268                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
269         self.assertTrue(len(res1) == 1)
270         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
271
272         m = Message()
273         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
274         m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
275           "userAccountControl")
276         ldb.modify(m)
277
278         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
279                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
280         self.assertTrue(len(res1) == 1)
281         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DOMAIN_MEMBERS))
282
283         m = Message()
284         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
285         m["userAccountControl"] = MessageElement(str(UF_SERVER_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
286           "userAccountControl")
287         ldb.modify(m)
288
289         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
290                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
291         self.assertTrue(len(res1) == 1)
292         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DCS))
293
294         # Read-only DC accounts are only creatable by
295         # UF_WORKSTATION_TRUST_ACCOUNT and work only on DCs >= 2008 (therefore
296         # we have a fallback in the assertion)
297         m = Message()
298         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
299         m["userAccountControl"] = MessageElement(str(UF_PARTIAL_SECRETS_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
300           "userAccountControl")
301         ldb.modify(m)
302
303         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
304                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
305         self.assertTrue(len(res1) == 1)
306         self.assertTrue(res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_READONLY_DCS) or
307                         res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_DOMAIN_MEMBERS))
308
309         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
310
311         # Recreate account for further tests
312
313         ldb.add({
314             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
315             "objectclass": "user"})
316
317         # Try to set an invalid account name
318         m = Message()
319         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
320         m["sAMAccountName"] = MessageElement("administrator", FLAG_MOD_REPLACE,
321           "sAMAccountName")
322         try:
323             ldb.modify(m)
324             self.fail()
325         except LdbError, (num, _):
326             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
327
328         # But to reset the actual "sAMAccountName" should still be possible
329         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
330                           scope=SCOPE_BASE, attrs=["sAMAccountName"])
331         self.assertTrue(len(res1) == 1)
332         m = Message()
333         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
334         m["sAMAccountName"] = MessageElement(res1[0]["sAMAccountName"][0], FLAG_MOD_REPLACE,
335           "sAMAccountName")
336         ldb.modify(m)
337
338         # And another (free) name should be possible as well
339         m = Message()
340         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
341         m["sAMAccountName"] = MessageElement("xxx_ldaptestuser_xxx", FLAG_MOD_REPLACE,
342           "sAMAccountName")
343         ldb.modify(m)
344
345         # We should be able to reset our actual primary group
346         m = Message()
347         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
348         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_USERS), FLAG_MOD_REPLACE,
349           "primaryGroupID")
350         ldb.modify(m)
351
352         # Try to add invalid primary group
353         m = Message()
354         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
355         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
356           "primaryGroupID")
357         try:
358             ldb.modify(m)
359             self.fail()
360         except LdbError, (num, _):
361             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
362
363         # Try to make group 1 primary - should be denied since it is not yet
364         # secondary
365         m = Message()
366         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
367         m["primaryGroupID"] = MessageElement(str(group_rid_1),
368           FLAG_MOD_REPLACE, "primaryGroupID")
369         try:
370             ldb.modify(m)
371             self.fail()
372         except LdbError, (num, _):
373             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
374
375         # Make group 1 secondary
376         m = Message()
377         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
378         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
379                                      FLAG_MOD_REPLACE, "member")
380         ldb.modify(m)
381
382         # Make group 1 primary
383         m = Message()
384         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
385         m["primaryGroupID"] = MessageElement(str(group_rid_1),
386           FLAG_MOD_REPLACE, "primaryGroupID")
387         ldb.modify(m)
388
389         # Try to delete group 1 - should be denied
390         try:
391             ldb.delete("cn=ldaptestgroup,cn=users," + self.base_dn)
392             self.fail()
393         except LdbError, (num, _):
394             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
395
396         # Try to add group 1 also as secondary - should be denied
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_ADD, "member")
401         try:
402             ldb.modify(m)
403             self.fail()
404         except LdbError, (num, _):
405             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
406
407         # Try to add invalid member to group 1 - should be denied
408         m = Message()
409         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
410         m["member"] = MessageElement(
411           "cn=ldaptestuser3,cn=users," + self.base_dn,
412           FLAG_MOD_ADD, "member")
413         try:
414             ldb.modify(m)
415             self.fail()
416         except LdbError, (num, _):
417             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
418
419         # Make group 2 secondary
420         m = Message()
421         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
422         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
423                                      FLAG_MOD_ADD, "member")
424         ldb.modify(m)
425
426         # Swap the groups
427         m = Message()
428         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
429         m["primaryGroupID"] = MessageElement(str(group_rid_2),
430           FLAG_MOD_REPLACE, "primaryGroupID")
431         ldb.modify(m)
432
433         # Swap the groups (does not really make sense but does the same)
434         m = Message()
435         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
436         m["primaryGroupID"] = MessageElement(str(group_rid_1),
437           FLAG_MOD_REPLACE, "primaryGroupID")
438         m["primaryGroupID"] = MessageElement(str(group_rid_2),
439           FLAG_MOD_REPLACE, "primaryGroupID")
440         ldb.modify(m)
441
442         # Old primary group should contain a "member" attribute for the user,
443         # the new shouldn't contain anymore one
444         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
445                           scope=SCOPE_BASE, attrs=["member"])
446         self.assertTrue(len(res1) == 1)
447         self.assertTrue(len(res1[0]["member"]) == 1)
448         self.assertEquals(res1[0]["member"][0].lower(),
449           ("cn=ldaptestuser,cn=users," + self.base_dn).lower())
450
451         res1 = ldb.search("cn=ldaptestgroup2, cn=users," + self.base_dn,
452                           scope=SCOPE_BASE, attrs=["member"])
453         self.assertTrue(len(res1) == 1)
454         self.assertFalse("member" in res1[0])
455
456         # Primary group member
457         m = Message()
458         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
459         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
460                                      FLAG_MOD_DELETE, "member")
461         try:
462             ldb.modify(m)
463             self.fail()
464         except LdbError, (num, _):
465             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
466
467         # Delete invalid group member
468         m = Message()
469         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
470         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
471                                      FLAG_MOD_DELETE, "member")
472         try:
473             ldb.modify(m)
474             self.fail()
475         except LdbError, (num, _):
476             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
477
478         # Also this should be denied
479         try:
480             ldb.add({
481               "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
482               "objectclass": "user",
483               "primaryGroupID": "0"})
484             self.fail()
485         except LdbError, (num, _):
486             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
487
488         # Recreate user accounts
489
490         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
491
492         ldb.add({
493             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
494             "objectclass": "user"})
495
496         ldb.add({
497             "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
498             "objectclass": "user"})
499
500         m = Message()
501         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
502         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
503                                      FLAG_MOD_ADD, "member")
504         ldb.modify(m)
505
506         # Already added
507         m = Message()
508         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
509         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
510                                      FLAG_MOD_ADD, "member")
511         try:
512             ldb.modify(m)
513             self.fail()
514         except LdbError, (num, _):
515             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
516
517         # Already added, but as <SID=...>
518         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
519                           scope=SCOPE_BASE, attrs=["objectSid"])
520         self.assertTrue(len(res1) == 1)
521         sid_bin = res1[0]["objectSid"][0]
522         sid_str = ("<SID=" + ldb.schema_format_value("objectSid", sid_bin) + ">").upper()
523
524         m = Message()
525         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
526         m["member"] = MessageElement(sid_str, FLAG_MOD_ADD, "member")
527         try:
528             ldb.modify(m)
529             self.fail()
530         except LdbError, (num, _):
531             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
532
533         # Invalid member
534         m = Message()
535         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
536         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
537                                      FLAG_MOD_REPLACE, "member")
538         try:
539             ldb.modify(m)
540             self.fail()
541         except LdbError, (num, _):
542             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
543
544         # Invalid member
545         m = Message()
546         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
547         m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn,
548                                       "cn=ldaptestuser1,cn=users," + self.base_dn],
549                                      FLAG_MOD_REPLACE, "member")
550         try:
551             ldb.modify(m)
552             self.fail()
553         except LdbError, (num, _):
554             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
555
556         # Invalid member
557         m = Message()
558         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
559         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
560                                      FLAG_MOD_REPLACE, "member")
561         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
562                                      FLAG_MOD_ADD, "member")
563         try:
564             ldb.modify(m)
565             self.fail()
566         except LdbError, (num, _):
567             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
568
569         m = Message()
570         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
571         m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn,
572                                       "cn=ldaptestuser2,cn=users," + self.base_dn],
573                                      FLAG_MOD_REPLACE, "member")
574         ldb.modify(m)
575
576         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
577         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
578         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
579         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
580
581         # Make also a small test for accounts with special DNs ("," in this case)
582         ldb.add({
583             "dn": "cn=ldaptest\,specialuser,cn=users," + self.base_dn,
584             "objectclass": "user"})
585         delete_force(self.ldb, "cn=ldaptest\,specialuser,cn=users," + self.base_dn)
586
587     def test_sam_attributes(self):
588         """Test the behaviour of special attributes of SAM objects"""
589         print "Testing the behaviour of special attributes of SAM objects\n"""
590
591         ldb.add({
592             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
593             "objectclass": "user"})
594         ldb.add({
595             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
596             "objectclass": "group"})
597
598         m = Message()
599         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
600         m["groupType"] = MessageElement(str(GTYPE_SECURITY_GLOBAL_GROUP), FLAG_MOD_ADD,
601           "groupType")
602         try:
603             ldb.modify(m)
604             self.fail()
605         except LdbError, (num, _):
606             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
607
608         # Delete protection tests
609
610         for attr in ["nTSecurityDescriptor", "objectSid", "sAMAccountType",
611                      "sAMAccountName", "groupType"]:
612
613             m = Message()
614             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
615             m[attr] = MessageElement([], FLAG_MOD_REPLACE, attr)
616             try:
617                 ldb.modify(m)
618                 self.fail()
619             except LdbError, (num, _):
620                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
621
622             m = Message()
623             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
624             m[attr] = MessageElement([], FLAG_MOD_DELETE, attr)
625             try:
626                 ldb.modify(m)
627                 self.fail()
628             except LdbError, (num, _):
629                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
630
631         m = Message()
632         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
633         m["primaryGroupID"] = MessageElement("513", FLAG_MOD_ADD,
634           "primaryGroupID")
635         try:
636             ldb.modify(m)
637             self.fail()
638         except LdbError, (num, _):
639             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
640
641         m = Message()
642         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
643         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_ADD,
644           "userAccountControl")
645         try:
646             ldb.modify(m)
647             self.fail()
648         except LdbError, (num, _):
649             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
650
651         m = Message()
652         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
653         m["objectSid"] = MessageElement("xxxxxxxxxxxxxxxx", FLAG_MOD_ADD,
654           "objectSid")
655         try:
656             ldb.modify(m)
657             self.fail()
658         except LdbError, (num, _):
659             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
660
661         m = Message()
662         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
663         m["sAMAccountType"] = MessageElement("0", FLAG_MOD_ADD,
664           "sAMAccountType")
665         try:
666             ldb.modify(m)
667             self.fail()
668         except LdbError, (num, _):
669             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
670
671         m = Message()
672         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
673         m["sAMAccountName"] = MessageElement("test", FLAG_MOD_ADD,
674           "sAMAccountName")
675         try:
676             ldb.modify(m)
677             self.fail()
678         except LdbError, (num, _):
679             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
680
681         # Delete protection tests
682
683         for attr in ["nTSecurityDescriptor", "objectSid", "sAMAccountType",
684                      "sAMAccountName", "primaryGroupID", "userAccountControl",
685                      "accountExpires", "badPasswordTime", "badPwdCount",
686                      "codePage", "countryCode", "lastLogoff", "lastLogon",
687                      "logonCount", "pwdLastSet"]:
688
689             m = Message()
690             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
691             m[attr] = MessageElement([], FLAG_MOD_REPLACE, attr)
692             try:
693                 ldb.modify(m)
694                 self.fail()
695             except LdbError, (num, _):
696                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
697
698             m = Message()
699             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
700             m[attr] = MessageElement([], FLAG_MOD_DELETE, attr)
701             try:
702                 ldb.modify(m)
703                 self.fail()
704             except LdbError, (num, _):
705                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
706
707         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
708         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
709
710     def test_primary_group_token_constructed(self):
711         """Test the primary group token behaviour (hidden-generated-readonly attribute on groups) and some other constructed attributes"""
712         print "Testing primary group token behaviour and other constructed attributes\n"
713
714         try:
715             ldb.add({
716                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
717                 "objectclass": "group",
718                 "primaryGroupToken": "100"})
719             self.fail()
720         except LdbError, (num, _):
721             self.assertEquals(num, ERR_UNDEFINED_ATTRIBUTE_TYPE)
722         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
723
724         ldb.add({
725             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
726             "objectclass": "user"})
727
728         ldb.add({
729             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
730             "objectclass": "group"})
731
732         # Testing for one invalid, and one valid operational attribute, but also the things they are built from
733         res1 = ldb.search(self.base_dn,
734                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName", "objectClass", "objectSid"])
735         self.assertTrue(len(res1) == 1)
736         self.assertFalse("primaryGroupToken" in res1[0])
737         self.assertTrue("canonicalName" in res1[0])
738         self.assertTrue("objectClass" in res1[0])
739         self.assertTrue("objectSid" in res1[0])
740
741         res1 = ldb.search(self.base_dn,
742                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName"])
743         self.assertTrue(len(res1) == 1)
744         self.assertFalse("primaryGroupToken" in res1[0])
745         self.assertFalse("objectSid" in res1[0])
746         self.assertFalse("objectClass" in res1[0])
747         self.assertTrue("canonicalName" in res1[0])
748
749         res1 = ldb.search("cn=users," + self.base_dn,
750                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
751         self.assertTrue(len(res1) == 1)
752         self.assertFalse("primaryGroupToken" in res1[0])
753
754         res1 = ldb.search("cn=ldaptestuser, cn=users," + self.base_dn,
755                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
756         self.assertTrue(len(res1) == 1)
757         self.assertFalse("primaryGroupToken" in res1[0])
758
759         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
760                           scope=SCOPE_BASE)
761         self.assertTrue(len(res1) == 1)
762         self.assertFalse("primaryGroupToken" in res1[0])
763
764         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
765                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "objectSID"])
766         self.assertTrue(len(res1) == 1)
767         primary_group_token = int(res1[0]["primaryGroupToken"][0])
768
769         rid = security.dom_sid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0])).split()[1]
770         self.assertEquals(primary_group_token, rid)
771
772         m = Message()
773         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
774         m["primaryGroupToken"] = "100"
775         try:
776             ldb.modify(m)
777             self.fail()
778         except LdbError, (num, _):
779             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
780
781         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
782         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
783
784     def test_tokenGroups(self):
785         """Test the tokenGroups behaviour (hidden-generated-readonly attribute on SAM objects)"""
786         print "Testing tokenGroups behaviour\n"
787
788         # The domain object shouldn't contain any "tokenGroups" entry
789         res = ldb.search(self.base_dn, scope=SCOPE_BASE, attrs=["tokenGroups"])
790         self.assertTrue(len(res) == 1)
791         self.assertFalse("tokenGroups" in res[0])
792
793         # The domain administrator should contain "tokenGroups" entries
794         # (the exact number depends on the domain/forest function level and the
795         # DC software versions)
796         res = ldb.search("cn=Administrator,cn=Users," + self.base_dn,
797                          scope=SCOPE_BASE, attrs=["tokenGroups"])
798         self.assertTrue(len(res) == 1)
799         self.assertTrue("tokenGroups" in res[0])
800
801         ldb.add({
802             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
803             "objectclass": "user"})
804
805         # This testuser should contain at least two "tokenGroups" entries
806         # (exactly two on an unmodified "Domain Users" and "Users" group)
807         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
808                          scope=SCOPE_BASE, attrs=["tokenGroups"])
809         self.assertTrue(len(res) == 1)
810         self.assertTrue(len(res[0]["tokenGroups"]) >= 2)
811
812         # one entry which we need to find should point to domains "Domain Users"
813         # group and another entry should point to the builtin "Users"group
814         domain_users_group_found = False
815         users_group_found = False
816         for sid in res[0]["tokenGroups"]:
817             rid = security.dom_sid(ldb.schema_format_value("objectSID", sid)).split()[1]
818             if rid == 513:
819                 domain_users_group_found = True
820             if rid == 545:
821                 users_group_found = True
822
823         self.assertTrue(domain_users_group_found)
824         self.assertTrue(users_group_found)
825
826         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
827
828     def test_groupType(self):
829         """Test the groupType behaviour"""
830         print "Testing groupType behaviour\n"
831
832         # You can never create or change to a
833         # "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP"
834
835         # Add operation
836
837         # Invalid attribute
838         try:
839             ldb.add({
840                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
841                 "objectclass": "group",
842                 "groupType": "0"})
843             self.fail()
844         except LdbError, (num, _):
845             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
846         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
847
848         try:
849             ldb.add({
850                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
851                 "objectclass": "group",
852                 "groupType": str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP)})
853             self.fail()
854         except LdbError, (num, _):
855             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
856         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
857
858         ldb.add({
859             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
860             "objectclass": "group",
861             "groupType": str(GTYPE_SECURITY_GLOBAL_GROUP)})
862
863         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
864                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
865         self.assertTrue(len(res1) == 1)
866         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
867           ATYPE_SECURITY_GLOBAL_GROUP)
868         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
869
870         ldb.add({
871             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
872             "objectclass": "group",
873             "groupType": str(GTYPE_SECURITY_UNIVERSAL_GROUP)})
874
875         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
876                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
877         self.assertTrue(len(res1) == 1)
878         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
879           ATYPE_SECURITY_UNIVERSAL_GROUP)
880         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
881
882         ldb.add({
883             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
884             "objectclass": "group",
885             "groupType": str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)})
886
887         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
888                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
889         self.assertTrue(len(res1) == 1)
890         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
891           ATYPE_SECURITY_LOCAL_GROUP)
892         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
893
894         ldb.add({
895             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
896             "objectclass": "group",
897             "groupType": str(GTYPE_DISTRIBUTION_GLOBAL_GROUP)})
898
899         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
900                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
901         self.assertTrue(len(res1) == 1)
902         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
903           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
904         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
905
906         ldb.add({
907             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
908             "objectclass": "group",
909             "groupType": str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP)})
910
911         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
912                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
913         self.assertTrue(len(res1) == 1)
914         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
915           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
916         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
917
918         ldb.add({
919             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
920             "objectclass": "group",
921             "groupType": str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)})
922
923         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
924                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
925         self.assertTrue(len(res1) == 1)
926         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
927           ATYPE_DISTRIBUTION_LOCAL_GROUP)
928         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
929
930         # Modify operation
931
932         ldb.add({
933             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
934             "objectclass": "group"})
935
936         # We can change in this direction: global <-> universal <-> local
937         # On each step also the group type itself (security/distribution) is
938         # variable.
939
940         # After creation we should have a "security global group"
941         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
942                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
943         self.assertTrue(len(res1) == 1)
944         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
945           ATYPE_SECURITY_GLOBAL_GROUP)
946
947         # Invalid attribute
948         try:
949             m = Message()
950             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
951             m["groupType"] = MessageElement("0",
952               FLAG_MOD_REPLACE, "groupType")
953             ldb.modify(m)
954             self.fail()
955         except LdbError, (num, _):
956             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
957
958         # Security groups
959
960         # Default is "global group"
961
962         m = Message()
963         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
964         m["groupType"] = MessageElement(
965           str(GTYPE_SECURITY_GLOBAL_GROUP),
966           FLAG_MOD_REPLACE, "groupType")
967         ldb.modify(m)
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_SECURITY_GLOBAL_GROUP)
974
975         # Change to "local" (shouldn't work)
976
977         try:
978             m = Message()
979             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
980             m["groupType"] = MessageElement(
981               str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
982               FLAG_MOD_REPLACE, "groupType")
983             ldb.modify(m)
984             self.fail()
985         except LdbError, (num, _):
986             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
987
988         # Change to "universal"
989
990         m = Message()
991         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
992         m["groupType"] = MessageElement(
993          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
994           FLAG_MOD_REPLACE, "groupType")
995         ldb.modify(m)
996
997         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
998                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
999         self.assertTrue(len(res1) == 1)
1000         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1001           ATYPE_SECURITY_UNIVERSAL_GROUP)
1002
1003         # Change back to "global"
1004
1005         m = Message()
1006         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1007         m["groupType"] = MessageElement(
1008           str(GTYPE_SECURITY_GLOBAL_GROUP),
1009           FLAG_MOD_REPLACE, "groupType")
1010         ldb.modify(m)
1011
1012         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1013                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1014         self.assertTrue(len(res1) == 1)
1015         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1016           ATYPE_SECURITY_GLOBAL_GROUP)
1017
1018         # Change back to "universal"
1019
1020         m = Message()
1021         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1022         m["groupType"] = MessageElement(
1023          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1024           FLAG_MOD_REPLACE, "groupType")
1025         ldb.modify(m)
1026
1027         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1028                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1029         self.assertTrue(len(res1) == 1)
1030         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1031           ATYPE_SECURITY_UNIVERSAL_GROUP)
1032
1033         # Change to "local"
1034
1035         m = Message()
1036         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1037         m["groupType"] = MessageElement(
1038           str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
1039           FLAG_MOD_REPLACE, "groupType")
1040         ldb.modify(m)
1041
1042         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1043                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1044         self.assertTrue(len(res1) == 1)
1045         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1046           ATYPE_SECURITY_LOCAL_GROUP)
1047
1048         # Change to "global" (shouldn't work)
1049
1050         try:
1051             m = Message()
1052             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1053             m["groupType"] = MessageElement(
1054               str(GTYPE_SECURITY_GLOBAL_GROUP),
1055               FLAG_MOD_REPLACE, "groupType")
1056             ldb.modify(m)
1057             self.fail()
1058         except LdbError, (num, _):
1059             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1060
1061         # Change to "builtin local" (shouldn't work)
1062
1063         try:
1064             m = Message()
1065             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1066             m["groupType"] = MessageElement(
1067               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1068               FLAG_MOD_REPLACE, "groupType")
1069             ldb.modify(m)
1070             self.fail()
1071         except LdbError, (num, _):
1072             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1073
1074         m = Message()
1075         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1076
1077         # Change back to "universal"
1078
1079         m = Message()
1080         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1081         m["groupType"] = MessageElement(
1082          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1083           FLAG_MOD_REPLACE, "groupType")
1084         ldb.modify(m)
1085
1086         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1087                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1088         self.assertTrue(len(res1) == 1)
1089         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1090           ATYPE_SECURITY_UNIVERSAL_GROUP)
1091
1092         # Change to "builtin local" (shouldn't work)
1093
1094         try:
1095             m = Message()
1096             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1097             m["groupType"] = MessageElement(
1098               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1099               FLAG_MOD_REPLACE, "groupType")
1100             ldb.modify(m)
1101             self.fail()
1102         except LdbError, (num, _):
1103             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1104
1105         # Change back to "global"
1106
1107         m = Message()
1108         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1109         m["groupType"] = MessageElement(
1110           str(GTYPE_SECURITY_GLOBAL_GROUP),
1111           FLAG_MOD_REPLACE, "groupType")
1112         ldb.modify(m)
1113
1114         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1115                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1116         self.assertTrue(len(res1) == 1)
1117         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1118           ATYPE_SECURITY_GLOBAL_GROUP)
1119
1120         # Change to "builtin local" (shouldn't work)
1121
1122         try:
1123             m = Message()
1124             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1125             m["groupType"] = MessageElement(
1126               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1127               FLAG_MOD_REPLACE, "groupType")
1128             ldb.modify(m)
1129             self.fail()
1130         except LdbError, (num, _):
1131             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1132
1133         # Distribution groups
1134
1135         # Default is "global group"
1136
1137         m = Message()
1138         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1139         m["groupType"] = MessageElement(
1140           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1141           FLAG_MOD_REPLACE, "groupType")
1142         ldb.modify(m)
1143
1144         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1145                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1146         self.assertTrue(len(res1) == 1)
1147         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1148           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1149
1150         # Change to local (shouldn't work)
1151
1152         try:
1153             m = Message()
1154             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1155             m["groupType"] = MessageElement(
1156               str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1157               FLAG_MOD_REPLACE, "groupType")
1158             ldb.modify(m)
1159             self.fail()
1160         except LdbError, (num, _):
1161             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1162
1163         # Change to "universal"
1164
1165         m = Message()
1166         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1167         m["groupType"] = MessageElement(
1168          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1169           FLAG_MOD_REPLACE, "groupType")
1170         ldb.modify(m)
1171
1172         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1173                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1174         self.assertTrue(len(res1) == 1)
1175         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1176           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1177
1178         # Change back to "global"
1179
1180         m = Message()
1181         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1182         m["groupType"] = MessageElement(
1183           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1184           FLAG_MOD_REPLACE, "groupType")
1185         ldb.modify(m)
1186
1187         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1188                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1189         self.assertTrue(len(res1) == 1)
1190         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1191           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1192
1193         # Change back to "universal"
1194
1195         m = Message()
1196         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1197         m["groupType"] = MessageElement(
1198          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1199           FLAG_MOD_REPLACE, "groupType")
1200         ldb.modify(m)
1201
1202         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1203                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1204         self.assertTrue(len(res1) == 1)
1205         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1206           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1207
1208         # Change to "local"
1209
1210         m = Message()
1211         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1212         m["groupType"] = MessageElement(
1213           str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1214           FLAG_MOD_REPLACE, "groupType")
1215         ldb.modify(m)
1216
1217         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1218                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1219         self.assertTrue(len(res1) == 1)
1220         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1221           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1222
1223         # Change to "global" (shouldn't work)
1224
1225         try:
1226             m = Message()
1227             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1228             m["groupType"] = MessageElement(
1229               str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1230               FLAG_MOD_REPLACE, "groupType")
1231             ldb.modify(m)
1232             self.fail()
1233         except LdbError, (num, _):
1234             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1235
1236         # Change back to "universal"
1237
1238         # Try to add invalid member to group 1 - should be denied
1239         m = Message()
1240         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1241         m["member"] = MessageElement(
1242           "cn=ldaptestuser3,cn=users," + self.base_dn,
1243           FLAG_MOD_ADD, "member")
1244         try:
1245             ldb.modify(m)
1246             self.fail()
1247         except LdbError, (num, _):
1248             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1249
1250         # Make group 2 secondary
1251         m = Message()
1252         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1253         m["groupType"] = MessageElement(
1254          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1255           FLAG_MOD_REPLACE, "groupType")
1256         ldb.modify(m)
1257
1258         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1259                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1260         self.assertTrue(len(res1) == 1)
1261         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1262           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1263
1264         # Change back to "global"
1265
1266         m = Message()
1267         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1268         m["groupType"] = MessageElement(
1269           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1270           FLAG_MOD_REPLACE, "groupType")
1271         ldb.modify(m)
1272
1273         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1274                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1275         self.assertTrue(len(res1) == 1)
1276         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1277           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1278
1279         # Both group types: this performs only random checks - all possibilities
1280         # would require too much code.
1281
1282         # Default is "global group"
1283
1284         m = Message()
1285         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1286         m["groupType"] = MessageElement(
1287           str(GTYPE_SECURITY_GLOBAL_GROUP),
1288           FLAG_MOD_REPLACE, "groupType")
1289         ldb.modify(m)
1290
1291         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1292                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1293         self.assertTrue(len(res1) == 1)
1294         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1295           ATYPE_SECURITY_GLOBAL_GROUP)
1296
1297         # Change to "local" (shouldn't work)
1298
1299         try:
1300             m = Message()
1301             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1302             m["groupType"] = MessageElement(
1303               str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1304               FLAG_MOD_REPLACE, "groupType")
1305             ldb.modify(m)
1306             self.fail()
1307         except LdbError, (num, _):
1308             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1309
1310         # Change to "universal"
1311
1312         m = Message()
1313         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1314         m["groupType"] = MessageElement(
1315          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1316           FLAG_MOD_REPLACE, "groupType")
1317         ldb.modify(m)
1318
1319         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1320                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1321         self.assertTrue(len(res1) == 1)
1322         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1323           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1324
1325         # Change back to "global"
1326
1327         m = Message()
1328         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1329         m["groupType"] = MessageElement(
1330           str(GTYPE_SECURITY_GLOBAL_GROUP),
1331           FLAG_MOD_REPLACE, "groupType")
1332         ldb.modify(m)
1333
1334         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1335                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1336         self.assertTrue(len(res1) == 1)
1337         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1338           ATYPE_SECURITY_GLOBAL_GROUP)
1339
1340         # Change back to "universal"
1341
1342         m = Message()
1343         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1344         m["groupType"] = MessageElement(
1345          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1346           FLAG_MOD_REPLACE, "groupType")
1347         ldb.modify(m)
1348
1349         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1350                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1351         self.assertTrue(len(res1) == 1)
1352         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1353           ATYPE_SECURITY_UNIVERSAL_GROUP)
1354
1355         # Change to "local"
1356
1357         m = Message()
1358         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1359         m["groupType"] = MessageElement(
1360           str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1361           FLAG_MOD_REPLACE, "groupType")
1362         ldb.modify(m)
1363
1364         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1365                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1366         self.assertTrue(len(res1) == 1)
1367         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1368           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1369
1370         # Change to "global" (shouldn't work)
1371
1372         try:
1373             m = Message()
1374             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1375             m["groupType"] = MessageElement(
1376               str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1377               FLAG_MOD_REPLACE, "groupType")
1378             ldb.modify(m)
1379             self.fail()
1380         except LdbError, (num, _):
1381             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1382
1383         # Change back to "universal"
1384
1385         m = Message()
1386         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1387         m["groupType"] = MessageElement(
1388          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1389           FLAG_MOD_REPLACE, "groupType")
1390         ldb.modify(m)
1391
1392         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1393                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1394         self.assertTrue(len(res1) == 1)
1395         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1396           ATYPE_SECURITY_UNIVERSAL_GROUP)
1397
1398         # Change back to "global"
1399
1400         m = Message()
1401         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1402         m["groupType"] = MessageElement(
1403           str(GTYPE_SECURITY_GLOBAL_GROUP),
1404           FLAG_MOD_REPLACE, "groupType")
1405         ldb.modify(m)
1406
1407         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1408                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1409         self.assertTrue(len(res1) == 1)
1410         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1411           ATYPE_SECURITY_GLOBAL_GROUP)
1412
1413         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1414
1415     def test_userAccountControl(self):
1416         """Test the userAccountControl behaviour"""
1417         print "Testing userAccountControl behaviour\n"
1418
1419         # With a user object
1420
1421         # Add operation
1422
1423         # As user you can only set a normal account.
1424         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1425         # password yet.
1426         # With SYSTEM rights you can set a interdomain trust account.
1427
1428         ldb.add({
1429             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1430             "objectclass": "user",
1431             "userAccountControl": "0"})
1432
1433         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1434                           scope=SCOPE_BASE,
1435                           attrs=["sAMAccountType", "userAccountControl"])
1436         self.assertTrue(len(res1) == 1)
1437         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1438           ATYPE_NORMAL_ACCOUNT)
1439         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
1440         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0)
1441         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1442
1443 # This has to wait until s4 supports it (needs a password module change)
1444 #        try:
1445 #            ldb.add({
1446 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1447 #                "objectclass": "user",
1448 #                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1449 #            self.fail()
1450 #        except LdbError, (num, _):
1451 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1452 #        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1453
1454         ldb.add({
1455             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1456             "objectclass": "user",
1457             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1458
1459         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1460                           scope=SCOPE_BASE,
1461                           attrs=["sAMAccountType", "userAccountControl"])
1462         self.assertTrue(len(res1) == 1)
1463         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1464           ATYPE_NORMAL_ACCOUNT)
1465         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
1466         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1467
1468         ldb.add({
1469             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1470             "objectclass": "user",
1471             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_LOCKOUT | UF_PASSWORD_EXPIRED)})
1472
1473         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1474                           scope=SCOPE_BASE,
1475                           attrs=["sAMAccountType", "userAccountControl", "lockoutTime", "pwdLastSet"])
1476         self.assertTrue(len(res1) == 1)
1477         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1478           ATYPE_NORMAL_ACCOUNT)
1479         self.assertTrue(int(res1[0]["userAccountControl"][0]) & (UF_LOCKOUT | UF_PASSWORD_EXPIRED) == 0)
1480         self.assertFalse("lockoutTime" in res1[0])
1481         self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
1482         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1483
1484         try:
1485             ldb.add({
1486                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1487                 "objectclass": "user",
1488                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1489             self.fail()
1490         except LdbError, (num, _):
1491             self.assertEquals(num, ERR_OTHER)
1492         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1493
1494         try:
1495             ldb.add({
1496                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1497                 "objectclass": "user",
1498                 "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1499             self.fail()
1500         except LdbError, (num, _):
1501             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1502         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1503
1504         try:
1505             ldb.add({
1506                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1507                 "objectclass": "user",
1508                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1509         except LdbError, (num, _):
1510             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1511         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1512
1513         try:
1514             ldb.add({
1515                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1516                 "objectclass": "user",
1517                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)})
1518         except LdbError, (num, _):
1519             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1520         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1521
1522 # This isn't supported yet in s4 - needs ACL module adaption
1523 #        try:
1524 #            ldb.add({
1525 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1526 #                "objectclass": "user",
1527 #                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1528 #            self.fail()
1529 #        except LdbError, (num, _):
1530 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1531 #        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1532
1533         # Modify operation
1534
1535         ldb.add({
1536             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1537             "objectclass": "user"})
1538
1539         # After creation we should have a normal account
1540         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1541                           scope=SCOPE_BASE,
1542                           attrs=["sAMAccountType", "userAccountControl"])
1543         self.assertTrue(len(res1) == 1)
1544         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1545           ATYPE_NORMAL_ACCOUNT)
1546         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
1547
1548         # As user you can only switch from a normal account to a workstation
1549         # trust account and back.
1550         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1551         # password yet.
1552         # With SYSTEM rights you can switch to a interdomain trust account.
1553
1554         # Invalid attribute
1555         try:
1556             m = Message()
1557             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1558             m["userAccountControl"] = MessageElement("0",
1559               FLAG_MOD_REPLACE, "userAccountControl")
1560             ldb.modify(m)
1561         except LdbError, (num, _):
1562             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1563
1564 # This has to wait until s4 supports it (needs a password module change)
1565 #        try:
1566 #            m = Message()
1567 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1568 #            m["userAccountControl"] = MessageElement(
1569 #              str(UF_NORMAL_ACCOUNT),
1570 #              FLAG_MOD_REPLACE, "userAccountControl")
1571 #            ldb.modify(m)
1572 #        except LdbError, (num, _):
1573 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1574
1575         m = Message()
1576         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1577         m["userAccountControl"] = MessageElement(
1578           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1579           FLAG_MOD_REPLACE, "userAccountControl")
1580         ldb.modify(m)
1581
1582         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1583                           scope=SCOPE_BASE,
1584                           attrs=["sAMAccountType", "userAccountControl"])
1585         self.assertTrue(len(res1) == 1)
1586         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1587           ATYPE_NORMAL_ACCOUNT)
1588         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
1589
1590         m = Message()
1591         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1592         m["userAccountControl"] = MessageElement(
1593           str(UF_ACCOUNTDISABLE),
1594           FLAG_MOD_REPLACE, "userAccountControl")
1595         ldb.modify(m)
1596
1597         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1598                           scope=SCOPE_BASE,
1599                           attrs=["sAMAccountType", "userAccountControl"])
1600         self.assertTrue(len(res1) == 1)
1601         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1602           ATYPE_NORMAL_ACCOUNT)
1603         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_NORMAL_ACCOUNT != 0)
1604         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
1605
1606         m = Message()
1607         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1608         m["lockoutTime"] = MessageElement(str(samba.unix2nttime(0)), FLAG_MOD_REPLACE, "lockoutTime")
1609         m["pwdLastSet"] = MessageElement(str(samba.unix2nttime(0)), FLAG_MOD_REPLACE, "pwdLastSet")
1610         ldb.modify(m)
1611
1612         m = Message()
1613         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1614         m["userAccountControl"] = MessageElement(
1615           str(UF_LOCKOUT | UF_PASSWORD_EXPIRED),
1616           FLAG_MOD_REPLACE, "userAccountControl")
1617         ldb.modify(m)
1618
1619         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1620                           scope=SCOPE_BASE,
1621                           attrs=["sAMAccountType", "userAccountControl", "lockoutTime", "pwdLastSet"])
1622         self.assertTrue(len(res1) == 1)
1623         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1624           ATYPE_NORMAL_ACCOUNT)
1625         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_NORMAL_ACCOUNT != 0)
1626         self.assertTrue(int(res1[0]["userAccountControl"][0]) & (UF_LOCKOUT | UF_PASSWORD_EXPIRED) == 0)
1627         self.assertTrue(int(res1[0]["lockoutTime"][0]) == 0)
1628         self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
1629
1630         try:
1631             m = Message()
1632             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1633             m["userAccountControl"] = MessageElement(
1634               str(UF_TEMP_DUPLICATE_ACCOUNT),
1635               FLAG_MOD_REPLACE, "userAccountControl")
1636             ldb.modify(m)
1637             self.fail()
1638         except LdbError, (num, _):
1639             self.assertEquals(num, ERR_OTHER)
1640
1641         try:
1642             m = Message()
1643             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1644             m["userAccountControl"] = MessageElement(
1645               str(UF_SERVER_TRUST_ACCOUNT),
1646               FLAG_MOD_REPLACE, "userAccountControl")
1647             ldb.modify(m)
1648             self.fail()
1649         except LdbError, (num, _):
1650             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1651
1652         m = Message()
1653         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1654         m["userAccountControl"] = MessageElement(
1655           str(UF_WORKSTATION_TRUST_ACCOUNT),
1656           FLAG_MOD_REPLACE, "userAccountControl")
1657         ldb.modify(m)
1658
1659         try:
1660             m = Message()
1661             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1662             m["userAccountControl"] = MessageElement(
1663               str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT),
1664               FLAG_MOD_REPLACE, "userAccountControl")
1665             ldb.modify(m)
1666             self.fail()
1667         except LdbError, (num, _):
1668             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1669
1670         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1671                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1672         self.assertTrue(len(res1) == 1)
1673         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1674           ATYPE_WORKSTATION_TRUST)
1675
1676         m = Message()
1677         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1678         m["userAccountControl"] = MessageElement(
1679           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1680           FLAG_MOD_REPLACE, "userAccountControl")
1681         ldb.modify(m)
1682
1683         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1684                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1685         self.assertTrue(len(res1) == 1)
1686         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1687           ATYPE_NORMAL_ACCOUNT)
1688
1689 # This isn't supported yet in s4 - needs ACL module adaption
1690 #        try:
1691 #            m = Message()
1692 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1693 #            m["userAccountControl"] = MessageElement(
1694 #              str(UF_INTERDOMAIN_TRUST_ACCOUNT),
1695 #              FLAG_MOD_REPLACE, "userAccountControl")
1696 #            ldb.modify(m)
1697 #            self.fail()
1698 #        except LdbError, (num, _):
1699 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1700
1701         # With a computer object
1702
1703         # Add operation
1704
1705         # As computer you can set a normal account and a server trust account.
1706         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1707         # password yet.
1708         # With SYSTEM rights you can set a interdomain trust account.
1709
1710         ldb.add({
1711             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1712             "objectclass": "computer",
1713             "userAccountControl": "0"})
1714
1715         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1716                           scope=SCOPE_BASE,
1717                           attrs=["sAMAccountType", "userAccountControl"])
1718         self.assertTrue(len(res1) == 1)
1719         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1720           ATYPE_NORMAL_ACCOUNT)
1721         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
1722         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_PASSWD_NOTREQD == 0)
1723         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1724
1725 # This has to wait until s4 supports it (needs a password module change)
1726 #        try:
1727 #            ldb.add({
1728 #                "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1729 #                "objectclass": "computer",
1730 #                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1731 #            self.fail()
1732 #        except LdbError, (num, _):
1733 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1734 #        delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1735
1736         ldb.add({
1737             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1738             "objectclass": "computer",
1739             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1740
1741         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1742                           scope=SCOPE_BASE,
1743                           attrs=["sAMAccountType", "userAccountControl"])
1744         self.assertTrue(len(res1) == 1)
1745         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1746           ATYPE_NORMAL_ACCOUNT)
1747         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
1748         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1749
1750         ldb.add({
1751             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1752             "objectclass": "computer",
1753             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_LOCKOUT | UF_PASSWORD_EXPIRED)})
1754
1755         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1756                           scope=SCOPE_BASE,
1757                           attrs=["sAMAccountType", "userAccountControl", "lockoutTime", "pwdLastSet"])
1758         self.assertTrue(len(res1) == 1)
1759         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1760           ATYPE_NORMAL_ACCOUNT)
1761         self.assertTrue(int(res1[0]["userAccountControl"][0]) & (UF_LOCKOUT | UF_PASSWORD_EXPIRED) == 0)
1762         self.assertFalse("lockoutTime" in res1[0])
1763         self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
1764         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1765
1766         try:
1767             ldb.add({
1768                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1769                 "objectclass": "computer",
1770                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1771             self.fail()
1772         except LdbError, (num, _):
1773             self.assertEquals(num, ERR_OTHER)
1774         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1775
1776         ldb.add({
1777             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1778             "objectclass": "computer",
1779             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1780
1781         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1782                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1783         self.assertTrue(len(res1) == 1)
1784         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1785           ATYPE_WORKSTATION_TRUST)
1786         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1787
1788         try:
1789             ldb.add({
1790                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1791                 "objectclass": "computer",
1792                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1793         except LdbError, (num, _):
1794             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1795         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1796
1797 # This isn't supported yet in s4 - needs ACL module adaption
1798 #        try:
1799 #            ldb.add({
1800 #                "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1801 #                "objectclass": "computer",
1802 #                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1803 #            self.fail()
1804 #        except LdbError, (num, _):
1805 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1806 #        delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1807
1808         # Modify operation
1809
1810         ldb.add({
1811             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1812             "objectclass": "computer"})
1813
1814         # After creation we should have a normal account
1815         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1816                           scope=SCOPE_BASE,
1817                           attrs=["sAMAccountType", "userAccountControl"])
1818         self.assertTrue(len(res1) == 1)
1819         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1820           ATYPE_NORMAL_ACCOUNT)
1821         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
1822
1823         # As computer you can switch from a normal account to a workstation
1824         # or server trust account and back (also swapping between trust
1825         # accounts is allowed).
1826         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1827         # password yet.
1828         # With SYSTEM rights you can switch to a interdomain trust account.
1829
1830         # Invalid attribute
1831         try:
1832             m = Message()
1833             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1834             m["userAccountControl"] = MessageElement("0",
1835               FLAG_MOD_REPLACE, "userAccountControl")
1836             ldb.modify(m)
1837         except LdbError, (num, _):
1838             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1839
1840 # This has to wait until s4 supports it (needs a password module change)
1841 #        try:
1842 #            m = Message()
1843 #            m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1844 #            m["userAccountControl"] = MessageElement(
1845 #              str(UF_NORMAL_ACCOUNT),
1846 #              FLAG_MOD_REPLACE, "userAccountControl")
1847 #            ldb.modify(m)
1848 #        except LdbError, (num, _):
1849 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1850
1851         m = Message()
1852         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1853         m["userAccountControl"] = MessageElement(
1854           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1855           FLAG_MOD_REPLACE, "userAccountControl")
1856         ldb.modify(m)
1857
1858         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1859                           scope=SCOPE_BASE,
1860                           attrs=["sAMAccountType", "userAccountControl"])
1861         self.assertTrue(len(res1) == 1)
1862         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1863           ATYPE_NORMAL_ACCOUNT)
1864         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
1865
1866         m = Message()
1867         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1868         m["userAccountControl"] = MessageElement(
1869           str(UF_ACCOUNTDISABLE),
1870           FLAG_MOD_REPLACE, "userAccountControl")
1871         ldb.modify(m)
1872
1873         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1874                           scope=SCOPE_BASE,
1875                           attrs=["sAMAccountType", "userAccountControl"])
1876         self.assertTrue(len(res1) == 1)
1877         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1878           ATYPE_NORMAL_ACCOUNT)
1879         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_NORMAL_ACCOUNT != 0)
1880         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE != 0)
1881
1882         m = Message()
1883         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1884         m["lockoutTime"] = MessageElement(str(samba.unix2nttime(0)), FLAG_MOD_REPLACE, "lockoutTime")
1885         m["pwdLastSet"] = MessageElement(str(samba.unix2nttime(0)), FLAG_MOD_REPLACE, "pwdLastSet")
1886         ldb.modify(m)
1887
1888         m = Message()
1889         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1890         m["userAccountControl"] = MessageElement(
1891           str(UF_LOCKOUT | UF_PASSWORD_EXPIRED),
1892           FLAG_MOD_REPLACE, "userAccountControl")
1893         ldb.modify(m)
1894
1895         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1896                           scope=SCOPE_BASE,
1897                           attrs=["sAMAccountType", "userAccountControl", "lockoutTime", "pwdLastSet"])
1898         self.assertTrue(len(res1) == 1)
1899         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1900           ATYPE_NORMAL_ACCOUNT)
1901         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_NORMAL_ACCOUNT != 0)
1902         self.assertTrue(int(res1[0]["userAccountControl"][0]) & (UF_LOCKOUT | UF_PASSWORD_EXPIRED) == 0)
1903         self.assertTrue(int(res1[0]["lockoutTime"][0]) == 0)
1904         self.assertTrue(int(res1[0]["pwdLastSet"][0]) == 0)
1905
1906         try:
1907             m = Message()
1908             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1909             m["userAccountControl"] = MessageElement(
1910               str(UF_TEMP_DUPLICATE_ACCOUNT),
1911               FLAG_MOD_REPLACE, "userAccountControl")
1912             ldb.modify(m)
1913             self.fail()
1914         except LdbError, (num, _):
1915             self.assertEquals(num, ERR_OTHER)
1916
1917         m = Message()
1918         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1919         m["userAccountControl"] = MessageElement(
1920           str(UF_SERVER_TRUST_ACCOUNT),
1921           FLAG_MOD_REPLACE, "userAccountControl")
1922         ldb.modify(m)
1923
1924         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1925                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1926         self.assertTrue(len(res1) == 1)
1927         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1928           ATYPE_WORKSTATION_TRUST)
1929
1930         m = Message()
1931         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1932         m["userAccountControl"] = MessageElement(
1933           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1934           FLAG_MOD_REPLACE, "userAccountControl")
1935         ldb.modify(m)
1936
1937         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1938                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1939         self.assertTrue(len(res1) == 1)
1940         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1941           ATYPE_NORMAL_ACCOUNT)
1942
1943         m = Message()
1944         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1945         m["userAccountControl"] = MessageElement(
1946           str(UF_WORKSTATION_TRUST_ACCOUNT),
1947           FLAG_MOD_REPLACE, "userAccountControl")
1948         ldb.modify(m)
1949
1950         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1951                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1952         self.assertTrue(len(res1) == 1)
1953         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1954           ATYPE_WORKSTATION_TRUST)
1955
1956         m = Message()
1957         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1958         m["userAccountControl"] = MessageElement(
1959           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1960           FLAG_MOD_REPLACE, "userAccountControl")
1961         ldb.modify(m)
1962
1963         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1964                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1965         self.assertTrue(len(res1) == 1)
1966         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1967           ATYPE_NORMAL_ACCOUNT)
1968
1969         m = Message()
1970         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1971         m["userAccountControl"] = MessageElement(
1972           str(UF_SERVER_TRUST_ACCOUNT),
1973           FLAG_MOD_REPLACE, "userAccountControl")
1974         ldb.modify(m)
1975
1976         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1977                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1978         self.assertTrue(len(res1) == 1)
1979         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1980           ATYPE_WORKSTATION_TRUST)
1981
1982         m = Message()
1983         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1984         m["userAccountControl"] = MessageElement(
1985           str(UF_WORKSTATION_TRUST_ACCOUNT),
1986           FLAG_MOD_REPLACE, "userAccountControl")
1987         ldb.modify(m)
1988
1989         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1990                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1991         self.assertTrue(len(res1) == 1)
1992         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1993           ATYPE_WORKSTATION_TRUST)
1994
1995 # This isn't supported yet in s4 - needs ACL module adaption
1996 #        try:
1997 #            m = Message()
1998 #            m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1999 #            m["userAccountControl"] = MessageElement(
2000 #              str(UF_INTERDOMAIN_TRUST_ACCOUNT),
2001 #              FLAG_MOD_REPLACE, "userAccountControl")
2002 #            ldb.modify(m)
2003 #            self.fail()
2004 #        except LdbError, (num, _):
2005 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
2006
2007         # "primaryGroupID" does not change if account type remains the same
2008
2009         # For a user account
2010
2011         ldb.add({
2012             "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
2013             "objectclass": "user",
2014             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)})
2015
2016         res1 = ldb.search("cn=ldaptestuser2,cn=users," + self.base_dn,
2017                           scope=SCOPE_BASE,
2018                           attrs=["userAccountControl"])
2019         self.assertTrue(len(res1) == 1)
2020         self.assertEquals(int(res1[0]["userAccountControl"][0]),
2021            UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
2022
2023         m = Message()
2024         m.dn = Dn(ldb, "<SID=" + ldb.get_domain_sid() + "-" + str(DOMAIN_RID_ADMINS) + ">")
2025         m["member"] = MessageElement(
2026           "cn=ldaptestuser2,cn=users," + self.base_dn, FLAG_MOD_ADD, "member")
2027         ldb.modify(m)
2028
2029         m = Message()
2030         m.dn = Dn(ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2031         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_ADMINS),
2032           FLAG_MOD_REPLACE, "primaryGroupID")
2033         ldb.modify(m)
2034
2035         m = Message()
2036         m.dn = Dn(ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2037         m["userAccountControl"] = MessageElement(
2038           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2039           FLAG_MOD_REPLACE, "userAccountControl")
2040         ldb.modify(m)
2041
2042         res1 = ldb.search("cn=ldaptestuser2,cn=users," + self.base_dn,
2043                           scope=SCOPE_BASE,
2044                           attrs=["userAccountControl", "primaryGroupID"])
2045         self.assertTrue(len(res1) == 1)
2046         self.assertTrue(int(res1[0]["userAccountControl"][0]) & UF_ACCOUNTDISABLE == 0)
2047         self.assertEquals(int(res1[0]["primaryGroupID"][0]), DOMAIN_RID_ADMINS)
2048
2049         # For a workstation account
2050
2051         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2052                           scope=SCOPE_BASE,
2053                           attrs=["primaryGroupID"])
2054         self.assertTrue(len(res1) == 1)
2055         self.assertEquals(int(res1[0]["primaryGroupID"][0]), DOMAIN_RID_DOMAIN_MEMBERS)
2056
2057         m = Message()
2058         m.dn = Dn(ldb, "<SID=" + ldb.get_domain_sid() + "-" + str(DOMAIN_RID_USERS) + ">")
2059         m["member"] = MessageElement(
2060           "cn=ldaptestcomputer,cn=computers," + self.base_dn, FLAG_MOD_ADD, "member")
2061         ldb.modify(m)
2062
2063         m = Message()
2064         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2065         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_USERS),
2066           FLAG_MOD_REPLACE, "primaryGroupID")
2067         ldb.modify(m)
2068
2069         m = Message()
2070         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2071         m["userAccountControl"] = MessageElement(
2072           str(UF_WORKSTATION_TRUST_ACCOUNT),
2073           FLAG_MOD_REPLACE, "userAccountControl")
2074         ldb.modify(m)
2075
2076         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2077                           scope=SCOPE_BASE,
2078                           attrs=["primaryGroupID"])
2079         self.assertTrue(len(res1) == 1)
2080         self.assertEquals(int(res1[0]["primaryGroupID"][0]), DOMAIN_RID_USERS)
2081
2082         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2083         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2084         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2085
2086     def test_isCriticalSystemObject(self):
2087         """Test the isCriticalSystemObject behaviour"""
2088         print "Testing isCriticalSystemObject behaviour\n"
2089
2090         # Add tests
2091
2092         ldb.add({
2093             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2094             "objectclass": "computer"})
2095
2096         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2097                           scope=SCOPE_BASE,
2098                           attrs=["isCriticalSystemObject"])
2099         self.assertTrue(len(res1) == 1)
2100         self.assertTrue("isCriticalSystemObject" not in res1[0])
2101
2102         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2103
2104         ldb.add({
2105             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2106             "objectclass": "computer",
2107             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
2108
2109         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2110                           scope=SCOPE_BASE,
2111                           attrs=["isCriticalSystemObject"])
2112         self.assertTrue(len(res1) == 1)
2113         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "FALSE")
2114
2115         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2116
2117         ldb.add({
2118             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2119             "objectclass": "computer",
2120             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)})
2121
2122         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2123                           scope=SCOPE_BASE,
2124                           attrs=["isCriticalSystemObject"])
2125         self.assertTrue(len(res1) == 1)
2126         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2127
2128         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2129
2130         ldb.add({
2131             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2132             "objectclass": "computer",
2133             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
2134
2135         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2136                           scope=SCOPE_BASE,
2137                           attrs=["isCriticalSystemObject"])
2138         self.assertTrue(len(res1) == 1)
2139         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2140
2141         # Modification tests
2142
2143         m = Message()
2144         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2145         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2146           FLAG_MOD_REPLACE, "userAccountControl")
2147         ldb.modify(m)
2148
2149         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2150                           scope=SCOPE_BASE,
2151                           attrs=["isCriticalSystemObject"])
2152         self.assertTrue(len(res1) == 1)
2153         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2154
2155         m = Message()
2156         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2157         m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT),
2158           FLAG_MOD_REPLACE, "userAccountControl")
2159         ldb.modify(m)
2160
2161         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2162                           scope=SCOPE_BASE,
2163                           attrs=["isCriticalSystemObject"])
2164         self.assertTrue(len(res1) == 1)
2165         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "FALSE")
2166
2167         m = Message()
2168         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2169         m["userAccountControl"] = MessageElement(
2170           str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT),
2171           FLAG_MOD_REPLACE, "userAccountControl")
2172         ldb.modify(m)
2173
2174         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2175                           scope=SCOPE_BASE,
2176                           attrs=["isCriticalSystemObject"])
2177         self.assertTrue(len(res1) == 1)
2178         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2179
2180         m = Message()
2181         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2182         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
2183           FLAG_MOD_REPLACE, "userAccountControl")
2184         ldb.modify(m)
2185
2186         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2187                           scope=SCOPE_BASE,
2188                           attrs=["isCriticalSystemObject"])
2189         self.assertTrue(len(res1) == 1)
2190         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2191
2192         m = Message()
2193         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2194         m["userAccountControl"] = MessageElement(str(UF_SERVER_TRUST_ACCOUNT),
2195           FLAG_MOD_REPLACE, "userAccountControl")
2196         ldb.modify(m)
2197
2198         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2199                           scope=SCOPE_BASE,
2200                           attrs=["isCriticalSystemObject"])
2201         self.assertTrue(len(res1) == 1)
2202         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "TRUE")
2203
2204         m = Message()
2205         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2206         m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT),
2207           FLAG_MOD_REPLACE, "userAccountControl")
2208         ldb.modify(m)
2209
2210         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2211                           scope=SCOPE_BASE,
2212                           attrs=["isCriticalSystemObject"])
2213         self.assertTrue(len(res1) == 1)
2214         self.assertEquals(res1[0]["isCriticalSystemObject"][0], "FALSE")
2215
2216         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2217
2218     def test_service_principal_name_updates(self):
2219         """Test the servicePrincipalNames update behaviour"""
2220         print "Testing servicePrincipalNames update behaviour\n"
2221
2222         ldb.add({
2223             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2224             "objectclass": "computer",
2225             "dNSHostName": "testname.testdom"})
2226
2227         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2228                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2229         self.assertTrue(len(res) == 1)
2230         self.assertFalse("servicePrincipalName" in res[0])
2231
2232         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2233
2234         ldb.add({
2235             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2236             "objectclass": "computer",
2237             "servicePrincipalName": "HOST/testname.testdom"})
2238
2239         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2240                           scope=SCOPE_BASE, attrs=["dNSHostName"])
2241         self.assertTrue(len(res) == 1)
2242         self.assertFalse("dNSHostName" in res[0])
2243
2244         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2245
2246         ldb.add({
2247             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2248             "objectclass": "computer",
2249             "dNSHostName": "testname2.testdom",
2250             "servicePrincipalName": "HOST/testname.testdom"})
2251
2252         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2253                          scope=SCOPE_BASE, attrs=["dNSHostName"])
2254         self.assertTrue(len(res) == 1)
2255         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
2256
2257         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2258                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2259         self.assertTrue(len(res) == 1)
2260         self.assertEquals(res[0]["servicePrincipalName"][0],
2261                           "HOST/testname.testdom")
2262
2263         m = Message()
2264         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2265         m["dNSHostName"] = MessageElement("testname.testdoM",
2266                                           FLAG_MOD_REPLACE, "dNSHostName")
2267         ldb.modify(m)
2268
2269         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2270                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2271         self.assertTrue(len(res) == 1)
2272         self.assertEquals(res[0]["servicePrincipalName"][0],
2273                           "HOST/testname.testdom")
2274
2275         m = Message()
2276         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2277         m["dNSHostName"] = MessageElement("testname2.testdom2",
2278                                           FLAG_MOD_REPLACE, "dNSHostName")
2279         ldb.modify(m)
2280
2281         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2282                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2283         self.assertTrue(len(res) == 1)
2284         self.assertEquals(res[0]["servicePrincipalName"][0],
2285                           "HOST/testname2.testdom2")
2286
2287         m = Message()
2288         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2289         m["dNSHostName"] = MessageElement([],
2290                                           FLAG_MOD_DELETE, "dNSHostName")
2291         ldb.modify(m)
2292
2293         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2294                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2295         self.assertTrue(len(res) == 1)
2296         self.assertEquals(res[0]["servicePrincipalName"][0],
2297                           "HOST/testname2.testdom2")
2298
2299         m = Message()
2300         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2301         m["dNSHostName"] = MessageElement("testname.testdom3",
2302                                           FLAG_MOD_REPLACE, "dNSHostName")
2303         ldb.modify(m)
2304
2305         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2306                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2307         self.assertTrue(len(res) == 1)
2308         self.assertEquals(res[0]["servicePrincipalName"][0],
2309                           "HOST/testname2.testdom2")
2310
2311         m = Message()
2312         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2313         m["dNSHostName"] = MessageElement("testname2.testdom2",
2314                                           FLAG_MOD_REPLACE, "dNSHostName")
2315         ldb.modify(m)
2316
2317         m = Message()
2318         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2319         m["dNSHostName"] = MessageElement("testname3.testdom3",
2320                                           FLAG_MOD_REPLACE, "dNSHostName")
2321         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom2",
2322                                                    FLAG_MOD_REPLACE,
2323                                                    "servicePrincipalName")
2324         ldb.modify(m)
2325
2326         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2327                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2328         self.assertTrue(len(res) == 1)
2329         self.assertEquals(res[0]["servicePrincipalName"][0],
2330                           "HOST/testname3.testdom3")
2331
2332         m = Message()
2333         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2334         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom2",
2335                                                    FLAG_MOD_REPLACE,
2336                                                    "servicePrincipalName")
2337         m["dNSHostName"] = MessageElement("testname4.testdom4",
2338                                           FLAG_MOD_REPLACE, "dNSHostName")
2339         ldb.modify(m)
2340
2341         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2342                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2343         self.assertTrue(len(res) == 1)
2344         self.assertEquals(res[0]["servicePrincipalName"][0],
2345                           "HOST/testname2.testdom2")
2346
2347         m = Message()
2348         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2349         m["servicePrincipalName"] = MessageElement([],
2350                                                    FLAG_MOD_DELETE,
2351                                                    "servicePrincipalName")
2352         ldb.modify(m)
2353
2354         m = Message()
2355         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2356         m["dNSHostName"] = MessageElement("testname2.testdom2",
2357                                           FLAG_MOD_REPLACE, "dNSHostName")
2358         ldb.modify(m)
2359
2360         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2361                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2362         self.assertTrue(len(res) == 1)
2363         self.assertFalse("servicePrincipalName" in res[0])
2364
2365         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2366
2367         ldb.add({
2368             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2369             "objectclass": "computer",
2370             "sAMAccountName": "testname$"})
2371
2372         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2373                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2374         self.assertTrue(len(res) == 1)
2375         self.assertFalse("servicePrincipalName" in res[0])
2376
2377         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2378
2379         ldb.add({
2380             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2381             "objectclass": "computer",
2382             "servicePrincipalName": "HOST/testname"})
2383
2384         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2385                          scope=SCOPE_BASE, attrs=["sAMAccountName"])
2386         self.assertTrue(len(res) == 1)
2387         self.assertTrue("sAMAccountName" in res[0])
2388
2389         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2390
2391         ldb.add({
2392             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2393             "objectclass": "computer",
2394             "sAMAccountName": "testname$",
2395             "servicePrincipalName": "HOST/testname"})
2396
2397         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2398                          scope=SCOPE_BASE, attrs=["sAMAccountName"])
2399         self.assertTrue(len(res) == 1)
2400         self.assertEquals(res[0]["sAMAccountName"][0], "testname$")
2401
2402         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2403                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2404         self.assertTrue(len(res) == 1)
2405         self.assertEquals(res[0]["servicePrincipalName"][0],
2406                           "HOST/testname")
2407
2408         m = Message()
2409         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2410         m["sAMAccountName"] = MessageElement("testnamE$",
2411                                              FLAG_MOD_REPLACE, "sAMAccountName")
2412         ldb.modify(m)
2413
2414         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2415                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2416         self.assertTrue(len(res) == 1)
2417         self.assertEquals(res[0]["servicePrincipalName"][0],
2418                           "HOST/testname")
2419
2420         m = Message()
2421         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2422         m["sAMAccountName"] = MessageElement("testname",
2423                                              FLAG_MOD_REPLACE, "sAMAccountName")
2424         ldb.modify(m)
2425
2426         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2427                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2428         self.assertTrue(len(res) == 1)
2429         self.assertEquals(res[0]["servicePrincipalName"][0],
2430                           "HOST/testname")
2431
2432         m = Message()
2433         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2434         m["sAMAccountName"] = MessageElement("test$name$",
2435                                              FLAG_MOD_REPLACE, "sAMAccountName")
2436         ldb.modify(m)
2437
2438         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2439                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2440         self.assertTrue(len(res) == 1)
2441         self.assertEquals(res[0]["servicePrincipalName"][0],
2442                           "HOST/test$name")
2443
2444         m = Message()
2445         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2446         m["sAMAccountName"] = MessageElement("testname2",
2447                                              FLAG_MOD_REPLACE, "sAMAccountName")
2448         ldb.modify(m)
2449
2450         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2451                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2452         self.assertTrue(len(res) == 1)
2453         self.assertEquals(res[0]["servicePrincipalName"][0],
2454                           "HOST/testname2")
2455
2456         m = Message()
2457         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2458         m["sAMAccountName"] = MessageElement("testname3",
2459                                              FLAG_MOD_REPLACE, "sAMAccountName")
2460         m["servicePrincipalName"] = MessageElement("HOST/testname2",
2461                                                    FLAG_MOD_REPLACE,
2462                                                    "servicePrincipalName")
2463         ldb.modify(m)
2464
2465         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2466                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2467         self.assertTrue(len(res) == 1)
2468         self.assertEquals(res[0]["servicePrincipalName"][0],
2469                           "HOST/testname3")
2470
2471         m = Message()
2472         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2473         m["servicePrincipalName"] = MessageElement("HOST/testname2",
2474                                                    FLAG_MOD_REPLACE,
2475                                                    "servicePrincipalName")
2476         m["sAMAccountName"] = MessageElement("testname4",
2477                                              FLAG_MOD_REPLACE, "sAMAccountName")
2478         ldb.modify(m)
2479
2480         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2481                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2482         self.assertTrue(len(res) == 1)
2483         self.assertEquals(res[0]["servicePrincipalName"][0],
2484                           "HOST/testname2")
2485
2486         m = Message()
2487         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2488         m["servicePrincipalName"] = MessageElement([],
2489                                                    FLAG_MOD_DELETE,
2490                                                    "servicePrincipalName")
2491         ldb.modify(m)
2492
2493         m = Message()
2494         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2495         m["sAMAccountName"] = MessageElement("testname2",
2496                                              FLAG_MOD_REPLACE, "sAMAccountName")
2497         ldb.modify(m)
2498
2499         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2500                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2501         self.assertTrue(len(res) == 1)
2502         self.assertFalse("servicePrincipalName" in res[0])
2503
2504         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2505
2506         ldb.add({
2507             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2508             "objectclass": "computer",
2509             "dNSHostName": "testname.testdom",
2510             "sAMAccountName": "testname$",
2511             "servicePrincipalName": [ "HOST/testname.testdom", "HOST/testname" ]
2512         })
2513
2514         m = Message()
2515         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2516         m["dNSHostName"] = MessageElement("testname2.testdom",
2517                                           FLAG_MOD_REPLACE, "dNSHostName")
2518         m["sAMAccountName"] = MessageElement("testname2$",
2519                                              FLAG_MOD_REPLACE, "sAMAccountName")
2520         ldb.modify(m)
2521
2522         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2523                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
2524         self.assertTrue(len(res) == 1)
2525         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
2526         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
2527         self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2" or
2528                         res[0]["servicePrincipalName"][1] == "HOST/testname2")
2529         self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2.testdom" or
2530                         res[0]["servicePrincipalName"][1] == "HOST/testname2.testdom")
2531
2532         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2533
2534         ldb.add({
2535             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2536             "objectclass": "computer",
2537             "dNSHostName": "testname.testdom",
2538             "sAMAccountName": "testname$",
2539             "servicePrincipalName": [ "HOST/testname.testdom", "HOST/testname" ]
2540         })
2541
2542         m = Message()
2543         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2544         m["sAMAccountName"] = MessageElement("testname2$",
2545                                              FLAG_MOD_REPLACE, "sAMAccountName")
2546         m["dNSHostName"] = MessageElement("testname2.testdom",
2547                                           FLAG_MOD_REPLACE, "dNSHostName")
2548         ldb.modify(m)
2549
2550         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2551                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
2552         self.assertTrue(len(res) == 1)
2553         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
2554         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
2555         self.assertTrue(len(res[0]["servicePrincipalName"]) == 2)
2556         self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"])
2557         self.assertTrue("HOST/testname2.testdom" in res[0]["servicePrincipalName"])
2558
2559         m = Message()
2560         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2561         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom",
2562                                                    FLAG_MOD_ADD, "servicePrincipalName")
2563         try:
2564             ldb.modify(m)
2565             self.fail()
2566         except LdbError, (num, _):
2567             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2568
2569         # test for case-insensitiveness
2570         m = Message()
2571         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2572         m["servicePrincipalName"] = MessageElement("HOST/TESTNAME2.TESTDOM",
2573                                                    FLAG_MOD_ADD, "servicePrincipalName")
2574         try:
2575             ldb.modify(m)
2576             self.fail()
2577         except LdbError, (num, _):
2578             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2579
2580         m = Message()
2581         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2582         m["servicePrincipalName"] = MessageElement("HOST/testname3",
2583                                                    FLAG_MOD_ADD, "servicePrincipalName")
2584         ldb.modify(m)
2585
2586         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2587                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
2588         self.assertTrue(len(res) == 1)
2589         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
2590         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
2591         self.assertTrue(len(res[0]["servicePrincipalName"]) == 3)
2592         self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"])
2593         self.assertTrue("HOST/testname3" in res[0]["servicePrincipalName"])
2594         self.assertTrue("HOST/testname2.testdom" in res[0]["servicePrincipalName"])
2595
2596         m = Message()
2597         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2598         m["dNSHostName"] = MessageElement("testname3.testdom",
2599                                           FLAG_MOD_REPLACE, "dNSHostName")
2600         m["servicePrincipalName"] = MessageElement("HOST/testname3.testdom",
2601                                                    FLAG_MOD_ADD, "servicePrincipalName")
2602         ldb.modify(m)
2603
2604         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2605                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
2606         self.assertTrue(len(res) == 1)
2607         self.assertEquals(res[0]["dNSHostName"][0], "testname3.testdom")
2608         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
2609         self.assertTrue(len(res[0]["servicePrincipalName"]) == 3)
2610         self.assertTrue("HOST/testname2" in res[0]["servicePrincipalName"])
2611         self.assertTrue("HOST/testname3" in res[0]["servicePrincipalName"])
2612         self.assertTrue("HOST/testname3.testdom" in res[0]["servicePrincipalName"])
2613
2614         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2615
2616     def test_sam_description_attribute(self):
2617         """Test SAM description attribute"""
2618         print "Test SAM description attribute"""
2619
2620         self.ldb.add({
2621             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2622             "description": "desc2",
2623             "objectclass": "group",
2624             "description": "desc1"})
2625
2626         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2627                          scope=SCOPE_BASE, attrs=["description"])
2628         self.assertTrue(len(res) == 1)
2629         self.assertTrue("description" in res[0])
2630         self.assertTrue(len(res[0]["description"]) == 1)
2631         self.assertEquals(res[0]["description"][0], "desc1")
2632
2633         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2634
2635         self.ldb.add({
2636             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2637             "objectclass": "group",
2638             "description": ["desc1", "desc2"]})
2639
2640         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2641                          scope=SCOPE_BASE, attrs=["description"])
2642         self.assertTrue(len(res) == 1)
2643         self.assertTrue("description" in res[0])
2644         self.assertTrue(len(res[0]["description"]) == 2)
2645         self.assertTrue(res[0]["description"][0] == "desc1" or
2646                         res[0]["description"][1] == "desc1")
2647         self.assertTrue(res[0]["description"][0] == "desc2" or
2648                         res[0]["description"][1] == "desc2")
2649
2650         m = Message()
2651         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2652         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
2653           "description")
2654         try:
2655             ldb.modify(m)
2656             self.fail()
2657         except LdbError, (num, _):
2658             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2659
2660         m = Message()
2661         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2662         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
2663           "description")
2664         ldb.modify(m)
2665
2666         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2667
2668         self.ldb.add({
2669             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2670             "objectclass": "group" })
2671
2672         m = Message()
2673         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2674         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
2675           "description")
2676         ldb.modify(m)
2677
2678         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2679                          scope=SCOPE_BASE, attrs=["description"])
2680         self.assertTrue(len(res) == 1)
2681         self.assertTrue("description" in res[0])
2682         self.assertTrue(len(res[0]["description"]) == 1)
2683         self.assertEquals(res[0]["description"][0], "desc1")
2684
2685         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2686
2687         self.ldb.add({
2688             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2689             "objectclass": "group",
2690             "description": ["desc1", "desc2"]})
2691
2692         m = Message()
2693         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2694         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
2695           "description")
2696         ldb.modify(m)
2697
2698         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2699                          scope=SCOPE_BASE, attrs=["description"])
2700         self.assertTrue(len(res) == 1)
2701         self.assertTrue("description" in res[0])
2702         self.assertTrue(len(res[0]["description"]) == 1)
2703         self.assertEquals(res[0]["description"][0], "desc1")
2704
2705         m = Message()
2706         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2707         m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
2708           "description")
2709         try:
2710             ldb.modify(m)
2711             self.fail()
2712         except LdbError, (num, _):
2713             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2714
2715         m = Message()
2716         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2717         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
2718           "description")
2719         try:
2720             ldb.modify(m)
2721             self.fail()
2722         except LdbError, (num, _):
2723             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
2724
2725         m = Message()
2726         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2727         m["description"] = MessageElement("desc1", FLAG_MOD_DELETE,
2728           "description")
2729         ldb.modify(m)
2730         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2731                          scope=SCOPE_BASE, attrs=["description"])
2732         self.assertTrue(len(res) == 1)
2733         self.assertFalse("description" in res[0])
2734
2735         m = Message()
2736         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2737         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
2738           "description")
2739         try:
2740             ldb.modify(m)
2741             self.fail()
2742         except LdbError, (num, _):
2743             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2744
2745         m = Message()
2746         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2747         m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
2748           "description")
2749         try:
2750             ldb.modify(m)
2751             self.fail()
2752         except LdbError, (num, _):
2753             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2754
2755         m = Message()
2756         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2757         m["description"] = MessageElement("desc1", FLAG_MOD_ADD,
2758           "description")
2759         ldb.modify(m)
2760
2761         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2762                          scope=SCOPE_BASE, attrs=["description"])
2763         self.assertTrue(len(res) == 1)
2764         self.assertTrue("description" in res[0])
2765         self.assertTrue(len(res[0]["description"]) == 1)
2766         self.assertEquals(res[0]["description"][0], "desc1")
2767
2768         m = Message()
2769         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2770         m.add(MessageElement("desc1", FLAG_MOD_DELETE, "description"))
2771         m.add(MessageElement("desc2", FLAG_MOD_ADD, "description"))
2772         ldb.modify(m)
2773
2774         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2775                          scope=SCOPE_BASE, attrs=["description"])
2776         self.assertTrue(len(res) == 1)
2777         self.assertTrue("description" in res[0])
2778         self.assertTrue(len(res[0]["description"]) == 1)
2779         self.assertEquals(res[0]["description"][0], "desc2")
2780
2781         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2782
2783
2784     def test_fSMORoleOwner_attribute(self):
2785         """Test fSMORoleOwner attribute"""
2786         print "Test fSMORoleOwner attribute"""
2787
2788         ds_service_name = self.ldb.get_dsServiceName()
2789
2790         # The "fSMORoleOwner" attribute can only be set to "nTDSDSA" entries,
2791         # invalid DNs return ERR_UNWILLING_TO_PERFORM
2792
2793         try:
2794             self.ldb.add({
2795                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2796                 "objectclass": "group",
2797                 "fSMORoleOwner": self.base_dn})
2798             self.fail()
2799         except LdbError, (num, _):
2800             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2801
2802         try:
2803             self.ldb.add({
2804                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2805                 "objectclass": "group",
2806                 "fSMORoleOwner": [] })
2807             self.fail()
2808         except LdbError, (num, _):
2809             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2810
2811         # We are able to set it to a valid "nTDSDSA" entry if the server is
2812         # capable of handling the role
2813
2814         self.ldb.add({
2815             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2816             "objectclass": "group",
2817             "fSMORoleOwner": ds_service_name })
2818
2819         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2820
2821         self.ldb.add({
2822             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2823             "objectclass": "group" })
2824
2825         m = Message()
2826         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2827         m.add(MessageElement(self.base_dn, FLAG_MOD_REPLACE, "fSMORoleOwner"))
2828         try:
2829             ldb.modify(m)
2830             self.fail()
2831         except LdbError, (num, _):
2832             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2833
2834         m = Message()
2835         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2836         m.add(MessageElement([], FLAG_MOD_REPLACE, "fSMORoleOwner"))
2837         try:
2838             ldb.modify(m)
2839             self.fail()
2840         except LdbError, (num, _):
2841             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2842
2843         # We are able to set it to a valid "nTDSDSA" entry if the server is
2844         # capable of handling the role
2845
2846         m = Message()
2847         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2848         m.add(MessageElement(ds_service_name, FLAG_MOD_REPLACE, "fSMORoleOwner"))
2849         ldb.modify(m)
2850
2851         # A clean-out works on plain entries, not master (schema, PDC...) DNs
2852
2853         m = Message()
2854         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2855         m.add(MessageElement([], FLAG_MOD_DELETE, "fSMORoleOwner"))
2856         ldb.modify(m)
2857
2858         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2859
2860
2861 if not "://" in host:
2862     if os.path.isfile(host):
2863         host = "tdb://%s" % host
2864     else:
2865         host = "ldap://%s" % host
2866
2867 ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp)
2868
2869 runner = SubunitTestRunner()
2870 rc = 0
2871 if not runner.run(unittest.makeSuite(SamTests)).wasSuccessful():
2872     rc = 1
2873 sys.exit(rc)