s4:sam.py - tests for "userAccountControl" attribute
[obnox/samba/samba-obnox.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 time
8 import base64
9 import os
10
11 sys.path.append("bin/python")
12 import samba
13 samba.ensure_external_module("subunit", "subunit/python")
14 samba.ensure_external_module("testtools", "testtools")
15
16 import samba.getopt as options
17
18 from samba.auth import system_session
19 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
20 from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
21 from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
22 from ldb import ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_OTHER, ERR_INVALID_DN_SYNTAX
23 from ldb import ERR_NO_SUCH_ATTRIBUTE
24 from ldb import ERR_OBJECT_CLASS_VIOLATION, ERR_NOT_ALLOWED_ON_RDN
25 from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION
26 from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE, ERR_INSUFFICIENT_ACCESS_RIGHTS
27 from ldb import Message, MessageElement, Dn
28 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
29 from samba import Ldb
30 from samba.dsdb import (UF_NORMAL_ACCOUNT, UF_INTERDOMAIN_TRUST_ACCOUNT,
31     UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT,
32     UF_PARTIAL_SECRETS_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT,
33     UF_PASSWD_NOTREQD, UF_ACCOUNTDISABLE, ATYPE_NORMAL_ACCOUNT,
34     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP, GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
35     GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP,
36     GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP, GTYPE_DISTRIBUTION_GLOBAL_GROUP,
37     GTYPE_DISTRIBUTION_UNIVERSAL_GROUP,
38     ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_UNIVERSAL_GROUP,
39     ATYPE_SECURITY_LOCAL_GROUP, ATYPE_DISTRIBUTION_GLOBAL_GROUP,
40     ATYPE_DISTRIBUTION_UNIVERSAL_GROUP, ATYPE_DISTRIBUTION_LOCAL_GROUP,
41     ATYPE_WORKSTATION_TRUST, SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE,
42     SYSTEM_FLAG_CONFIG_ALLOW_RENAME, SYSTEM_FLAG_CONFIG_ALLOW_MOVE,
43     SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE)
44 from samba.dcerpc.security import (DOMAIN_RID_USERS, DOMAIN_RID_DOMAIN_MEMBERS,
45     DOMAIN_RID_DCS, DOMAIN_RID_READONLY_DCS)
46
47 from subunit.run import SubunitTestRunner
48 import unittest
49
50 from samba.ndr import ndr_pack, ndr_unpack
51 from samba.dcerpc import security
52
53 parser = optparse.OptionParser("sam.py [options] <host>")
54 sambaopts = options.SambaOptions(parser)
55 parser.add_option_group(sambaopts)
56 parser.add_option_group(options.VersionOptions(parser))
57 # use command line creds if available
58 credopts = options.CredentialsOptions(parser)
59 parser.add_option_group(credopts)
60 opts, args = parser.parse_args()
61
62 if len(args) < 1:
63     parser.print_usage()
64     sys.exit(1)
65
66 host = args[0]
67
68 lp = sambaopts.get_loadparm()
69 creds = credopts.get_credentials(lp)
70
71 class SamTests(unittest.TestCase):
72
73     def delete_force(self, ldb, dn):
74         try:
75             ldb.delete(dn)
76         except LdbError, (num, _):
77             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
78
79     def find_basedn(self, ldb):
80         res = ldb.search(base="", expression="", scope=SCOPE_BASE,
81                          attrs=["defaultNamingContext"])
82         self.assertEquals(len(res), 1)
83         return res[0]["defaultNamingContext"][0]
84
85     def find_domain_sid(self):
86         res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
87         return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
88
89     def setUp(self):
90         super(SamTests, self).setUp()
91         self.ldb = ldb
92         self.gc_ldb = gc_ldb
93         self.base_dn = self.find_basedn(ldb)
94         self.domain_sid = self.find_domain_sid()
95
96         print "baseDN: %s\n" % self.base_dn
97
98         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
99         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=users," + self.base_dn)
100         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
101         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
102
103     def test_users_groups(self):
104         """This tests the SAM users and groups behaviour"""
105         print "Testing users and groups behaviour\n"
106
107         ldb.add({
108             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
109             "objectclass": "group"})
110
111         ldb.add({
112             "dn": "cn=ldaptestgroup2,cn=users," + self.base_dn,
113             "objectclass": "group"})
114
115         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
116                           scope=SCOPE_BASE, attrs=["objectSID"])
117         self.assertTrue(len(res1) == 1)
118         group_rid_1 = security.dom_sid(ldb.schema_format_value("objectSID",
119           res1[0]["objectSID"][0])).split()[1]
120
121         res1 = ldb.search("cn=ldaptestgroup2,cn=users," + self.base_dn,
122                           scope=SCOPE_BASE, attrs=["objectSID"])
123         self.assertTrue(len(res1) == 1)
124         group_rid_2 = security.dom_sid(ldb.schema_format_value("objectSID",
125           res1[0]["objectSID"][0])).split()[1]
126
127         # Try to create a user with an invalid primary group
128         try:
129             ldb.add({
130                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
131                 "objectclass": ["user", "person"],
132                 "primaryGroupID": "0"})
133             self.fail()
134         except LdbError, (num, _):
135             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
136         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
137
138         # Try to Create a user with a valid primary group
139         try:
140             ldb.add({
141                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
142                 "objectclass": ["user", "person"],
143                 "primaryGroupID": str(group_rid_1)})
144             self.fail()
145         except LdbError, (num, _):
146             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
147         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
148
149         # Test to see how we should behave when the user account doesn't
150         # exist
151         m = Message()
152         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
153         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
154           "primaryGroupID")
155         try:
156             ldb.modify(m)
157             self.fail()
158         except LdbError, (num, _):
159             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
160
161         # Test to see how we should behave when the account isn't a user
162         m = Message()
163         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
164         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
165           "primaryGroupID")
166         try:
167             ldb.modify(m)
168             self.fail()
169         except LdbError, (num, _):
170             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
171
172         # Test default primary groups on add operations
173
174         ldb.add({
175             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
176             "objectclass": ["user", "person"]})
177
178         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
179                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
180         self.assertTrue(len(res1) == 1)
181         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
182
183         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
184
185         ldb.add({
186             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
187             "objectclass": ["user", "person"],
188             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD) })
189
190         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
191                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
192         self.assertTrue(len(res1) == 1)
193         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
194
195         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
196
197         # unfortunately the INTERDOMAIN_TRUST_ACCOUNT case cannot be tested
198         # since such accounts aren't directly creatable (ACCESS_DENIED)
199
200         ldb.add({
201             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
202             "objectclass": ["computer"],
203             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
204
205         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
206                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
207         self.assertTrue(len(res1) == 1)
208         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DOMAIN_MEMBERS))
209
210         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
211
212         ldb.add({
213             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
214             "objectclass": ["computer"],
215             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
216
217         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
218                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
219         self.assertTrue(len(res1) == 1)
220         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DCS))
221
222         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
223
224         # Read-only DC accounts are only creatable by
225         # UF_WORKSTATION_TRUST_ACCOUNT and work only on DCs >= 2008 (therefore
226         # we have a fallback in the assertion)
227         ldb.add({
228             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
229             "objectclass": ["computer"],
230             "userAccountControl": str(UF_PARTIAL_SECRETS_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
231
232         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
233                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
234         self.assertTrue(len(res1) == 1)
235         self.assertTrue(res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_READONLY_DCS) or
236                         res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_DOMAIN_MEMBERS))
237
238         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
239
240         # Test default primary groups on modify operations
241
242         ldb.add({
243             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
244             "objectclass": ["user", "person"]})
245
246         m = Message()
247         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
248         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
249           "userAccountControl")
250         ldb.modify(m)
251
252         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
253                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
254         self.assertTrue(len(res1) == 1)
255         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
256
257         # unfortunately the INTERDOMAIN_TRUST_ACCOUNT case cannot be tested
258         # since such accounts aren't directly creatable (ACCESS_DENIED)
259
260         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
261
262         ldb.add({
263             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
264             "objectclass": ["computer"]})
265
266         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
267                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
268         self.assertTrue(len(res1) == 1)
269         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
270
271         m = Message()
272         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
273         m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
274           "userAccountControl")
275         ldb.modify(m)
276
277         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
278                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
279         self.assertTrue(len(res1) == 1)
280         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DOMAIN_MEMBERS))
281
282         m = Message()
283         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
284         m["userAccountControl"] = MessageElement(str(UF_SERVER_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
285           "userAccountControl")
286         ldb.modify(m)
287
288         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
289                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
290         self.assertTrue(len(res1) == 1)
291         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DCS))
292
293         # Read-only DC accounts are only creatable by
294         # UF_WORKSTATION_TRUST_ACCOUNT and work only on DCs >= 2008 (therefore
295         # we have a fallback in the assertion)
296         m = Message()
297         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
298         m["userAccountControl"] = MessageElement(str(UF_PARTIAL_SECRETS_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
299           "userAccountControl")
300         ldb.modify(m)
301
302         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
303                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
304         self.assertTrue(len(res1) == 1)
305         self.assertTrue(res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_READONLY_DCS) or
306                         res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_DOMAIN_MEMBERS))
307
308         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
309
310         # Recreate account for further tests
311
312         ldb.add({
313             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
314             "objectclass": ["user", "person"]})
315
316         # We should be able to reset our actual primary group
317         m = Message()
318         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
319         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_USERS), FLAG_MOD_REPLACE,
320           "primaryGroupID")
321         ldb.modify(m)
322
323         # Try to add invalid primary group
324         m = Message()
325         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
326         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
327           "primaryGroupID")
328         try:
329             ldb.modify(m)
330             self.fail()
331         except LdbError, (num, _):
332             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
333
334         # Try to make group 1 primary - should be denied since it is not yet
335         # secondary
336         m = Message()
337         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
338         m["primaryGroupID"] = MessageElement(str(group_rid_1),
339           FLAG_MOD_REPLACE, "primaryGroupID")
340         try:
341             ldb.modify(m)
342             self.fail()
343         except LdbError, (num, _):
344             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
345
346         # Make group 1 secondary
347         m = Message()
348         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
349         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
350                                      FLAG_MOD_REPLACE, "member")
351         ldb.modify(m)
352
353         # Make group 1 primary
354         m = Message()
355         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
356         m["primaryGroupID"] = MessageElement(str(group_rid_1),
357           FLAG_MOD_REPLACE, "primaryGroupID")
358         ldb.modify(m)
359
360         # Try to delete group 1 - should be denied
361         try:
362             ldb.delete("cn=ldaptestgroup,cn=users," + self.base_dn)
363             self.fail()
364         except LdbError, (num, _):
365             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
366
367         # Try to add group 1 also as secondary - should be denied
368         m = Message()
369         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
370         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
371                                      FLAG_MOD_ADD, "member")
372         try:
373             ldb.modify(m)
374             self.fail()
375         except LdbError, (num, _):
376             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
377
378         # Try to add invalid member to group 1 - should be denied
379         m = Message()
380         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
381         m["member"] = MessageElement(
382           "cn=ldaptestuser3,cn=users," + self.base_dn,
383           FLAG_MOD_ADD, "member")
384         try:
385             ldb.modify(m)
386             self.fail()
387         except LdbError, (num, _):
388             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
389
390         # Make group 2 secondary
391         m = Message()
392         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
393         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
394                                      FLAG_MOD_ADD, "member")
395         ldb.modify(m)
396
397         # Swap the groups
398         m = Message()
399         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
400         m["primaryGroupID"] = MessageElement(str(group_rid_2),
401           FLAG_MOD_REPLACE, "primaryGroupID")
402         ldb.modify(m)
403
404         # Old primary group should contain a "member" attribute for the user,
405         # the new shouldn't contain anymore one
406         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
407                           scope=SCOPE_BASE, attrs=["member"])
408         self.assertTrue(len(res1) == 1)
409         self.assertTrue(len(res1[0]["member"]) == 1)
410         self.assertEquals(res1[0]["member"][0].lower(),
411           ("cn=ldaptestuser,cn=users," + self.base_dn).lower())
412
413         res1 = ldb.search("cn=ldaptestgroup2, cn=users," + self.base_dn,
414                           scope=SCOPE_BASE, attrs=["member"])
415         self.assertTrue(len(res1) == 1)
416         self.assertFalse("member" in res1[0])
417
418         # Also this should be denied
419         try:
420             ldb.add({
421               "dn": "cn=ldaptestuser1,cn=users," + self.base_dn,
422               "objectclass": ["user", "person"],
423               "primaryGroupID": "0"})
424             self.fail()
425         except LdbError, (num, _):
426             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
427
428         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
429         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
430         self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
431
432     def test_sam_attributes(self):
433         """Test the behaviour of special attributes of SAM objects"""
434         print "Testing the behaviour of special attributes of SAM objects\n"""
435
436         ldb.add({
437             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
438             "objectclass": ["user", "person"]})
439         ldb.add({
440             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
441             "objectclass": "group"})
442
443         m = Message()
444         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
445         m["groupType"] = MessageElement("0", FLAG_MOD_ADD,
446           "groupType")
447         try:
448             ldb.modify(m)
449             self.fail()
450         except LdbError, (num, _):
451             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
452
453         m = Message()
454         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
455         m["groupType"] = MessageElement([], FLAG_MOD_DELETE,
456           "groupType")
457         try:
458             ldb.modify(m)
459             self.fail()
460         except LdbError, (num, _):
461             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
462
463         m = Message()
464         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
465         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_ADD,
466           "primaryGroupID")
467         try:
468             ldb.modify(m)
469             self.fail()
470         except LdbError, (num, _):
471             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
472
473         m = Message()
474         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
475         m["primaryGroupID"] = MessageElement([], FLAG_MOD_DELETE,
476           "primaryGroupID")
477         try:
478             ldb.modify(m)
479             self.fail()
480         except LdbError, (num, _):
481             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
482
483         m = Message()
484         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
485         m["userAccountControl"] = MessageElement("0", FLAG_MOD_ADD,
486           "userAccountControl")
487         try:
488             ldb.modify(m)
489             self.fail()
490         except LdbError, (num, _):
491             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
492
493         m = Message()
494         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
495         m["userAccountControl"] = MessageElement([], FLAG_MOD_DELETE,
496           "userAccountControl")
497         try:
498             ldb.modify(m)
499             self.fail()
500         except LdbError, (num, _):
501             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
502
503         m = Message()
504         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
505         m["sAMAccountType"] = MessageElement("0", FLAG_MOD_ADD,
506           "sAMAccountType")
507         try:
508             ldb.modify(m)
509             self.fail()
510         except LdbError, (num, _):
511             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
512
513         m = Message()
514         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
515         m["sAMAccountType"] = MessageElement([], FLAG_MOD_REPLACE,
516           "sAMAccountType")
517         try:
518             ldb.modify(m)
519             self.fail()
520         except LdbError, (num, _):
521             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
522
523         m = Message()
524         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
525         m["sAMAccountType"] = MessageElement([], FLAG_MOD_DELETE,
526           "sAMAccountType")
527         try:
528             ldb.modify(m)
529             self.fail()
530         except LdbError, (num, _):
531             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
532
533         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
534         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
535
536     def test_primary_group_token_constructed(self):
537         """Test the primary group token behaviour (hidden-generated-readonly attribute on groups) and some other constructed attributes"""
538         print "Testing primary group token behaviour and other constructed attributes\n"
539
540         try:
541             ldb.add({
542                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
543                 "objectclass": "group",
544                 "primaryGroupToken": "100"})
545             self.fail()
546         except LdbError, (num, _):
547             self.assertEquals(num, ERR_UNDEFINED_ATTRIBUTE_TYPE)
548         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
549
550         ldb.add({
551             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
552             "objectclass": ["user", "person"]})
553
554         ldb.add({
555             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
556             "objectclass": "group"})
557
558         # Testing for one invalid, and one valid operational attribute, but also the things they are built from
559         res1 = ldb.search(self.base_dn,
560                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName", "objectClass", "objectSid"])
561         self.assertTrue(len(res1) == 1)
562         self.assertFalse("primaryGroupToken" in res1[0])
563         self.assertTrue("canonicalName" in res1[0])
564         self.assertTrue("objectClass" in res1[0])
565         self.assertTrue("objectSid" in res1[0])
566
567         res1 = ldb.search(self.base_dn,
568                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName"])
569         self.assertTrue(len(res1) == 1)
570         self.assertFalse("primaryGroupToken" in res1[0])
571         self.assertFalse("objectSid" in res1[0])
572         self.assertFalse("objectClass" in res1[0])
573         self.assertTrue("canonicalName" in res1[0])
574
575         res1 = ldb.search("cn=users," + self.base_dn,
576                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
577         self.assertTrue(len(res1) == 1)
578         self.assertFalse("primaryGroupToken" in res1[0])
579
580         res1 = ldb.search("cn=ldaptestuser, cn=users," + self.base_dn,
581                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
582         self.assertTrue(len(res1) == 1)
583         self.assertFalse("primaryGroupToken" in res1[0])
584
585         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
586                           scope=SCOPE_BASE)
587         self.assertTrue(len(res1) == 1)
588         self.assertFalse("primaryGroupToken" in res1[0])
589
590         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
591                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "objectSID"])
592         self.assertTrue(len(res1) == 1)
593         primary_group_token = int(res1[0]["primaryGroupToken"][0])
594
595         rid = security.dom_sid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0])).split()[1]
596         self.assertEquals(primary_group_token, rid)
597
598         m = Message()
599         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
600         m["primaryGroupToken"] = "100"
601         try:
602             ldb.modify(m)
603             self.fail()
604         except LdbError, (num, _):
605             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
606
607         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
608         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
609
610     def test_tokenGroups(self):
611         """Test the tokenGroups behaviour (hidden-generated-readonly attribute on SAM objects)"""
612         print "Testing tokenGroups behaviour\n"
613
614         # The domain object shouldn't contain any "tokenGroups" entry
615         res = ldb.search(self.base_dn, scope=SCOPE_BASE, attrs=["tokenGroups"])
616         self.assertTrue(len(res) == 1)
617         self.assertFalse("tokenGroups" in res[0])
618
619         # The domain administrator should contain "tokenGroups" entries
620         # (the exact number depends on the domain/forest function level and the
621         # DC software versions)
622         res = ldb.search("cn=Administrator,cn=Users," + self.base_dn,
623                          scope=SCOPE_BASE, attrs=["tokenGroups"])
624         self.assertTrue(len(res) == 1)
625         self.assertTrue("tokenGroups" in res[0])
626
627         ldb.add({
628             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
629             "objectclass": ["user", "person"]})
630
631         # This testuser should contain at least two "tokenGroups" entries
632         # (exactly two on an unmodified "Domain Users" and "Users" group)
633         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
634                          scope=SCOPE_BASE, attrs=["tokenGroups"])
635         self.assertTrue(len(res) == 1)
636         self.assertTrue(len(res[0]["tokenGroups"]) >= 2)
637
638         # one entry which we need to find should point to domains "Domain Users"
639         # group and another entry should point to the builtin "Users"group
640         domain_users_group_found = False
641         users_group_found = False
642         for sid in res[0]["tokenGroups"]:
643             rid = security.dom_sid(ldb.schema_format_value("objectSID", sid)).split()[1]
644             if rid == 513:
645                 domain_users_group_found = True
646             if rid == 545:
647                 users_group_found = True
648
649         self.assertTrue(domain_users_group_found)
650         self.assertTrue(users_group_found)
651
652         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
653
654     def test_groupType(self):
655         """Test the groupType behaviour"""
656         print "Testing groupType behaviour\n"
657
658         # You can never create or change to a
659         # "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP"
660
661         # Add operation
662
663         # Invalid attribute
664         try:
665             ldb.add({
666                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
667                 "objectclass": "group",
668                 "groupType": "0"})
669             self.fail()
670         except LdbError, (num, _):
671             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
672         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
673
674         try:
675             ldb.add({
676                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
677                 "objectclass": "group",
678                 "groupType": str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP)})
679             self.fail()
680         except LdbError, (num, _):
681             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
682         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
683
684         ldb.add({
685             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
686             "objectclass": "group",
687             "groupType": str(GTYPE_SECURITY_GLOBAL_GROUP)})
688
689         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
690                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
691         self.assertTrue(len(res1) == 1)
692         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
693           ATYPE_SECURITY_GLOBAL_GROUP)
694         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
695
696         ldb.add({
697             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
698             "objectclass": "group",
699             "groupType": str(GTYPE_SECURITY_UNIVERSAL_GROUP)})
700
701         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
702                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
703         self.assertTrue(len(res1) == 1)
704         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
705           ATYPE_SECURITY_UNIVERSAL_GROUP)
706         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
707
708         ldb.add({
709             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
710             "objectclass": "group",
711             "groupType": str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)})
712
713         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
714                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
715         self.assertTrue(len(res1) == 1)
716         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
717           ATYPE_SECURITY_LOCAL_GROUP)
718         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
719
720         ldb.add({
721             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
722             "objectclass": "group",
723             "groupType": str(GTYPE_DISTRIBUTION_GLOBAL_GROUP)})
724
725         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
726                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
727         self.assertTrue(len(res1) == 1)
728         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
729           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
730         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
731
732         ldb.add({
733             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
734             "objectclass": "group",
735             "groupType": str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP)})
736
737         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
738                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
739         self.assertTrue(len(res1) == 1)
740         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
741           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
742         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
743
744         ldb.add({
745             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
746             "objectclass": "group",
747             "groupType": str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)})
748
749         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
750                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
751         self.assertTrue(len(res1) == 1)
752         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
753           ATYPE_DISTRIBUTION_LOCAL_GROUP)
754         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
755
756         # Modify operation
757
758         ldb.add({
759             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
760             "objectclass": "group"})
761
762         # We can change in this direction: global <-> universal <-> local
763         # On each step also the group type itself (security/distribution) is
764         # variable.
765
766         # After creation we should have a "security global group"
767         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
768                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
769         self.assertTrue(len(res1) == 1)
770         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
771           ATYPE_SECURITY_GLOBAL_GROUP)
772
773         # Invalid attribute
774         try:
775             m = Message()
776             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
777             m["groupType"] = MessageElement("0",
778               FLAG_MOD_REPLACE, "groupType")
779             ldb.modify(m)
780             self.fail()
781         except LdbError, (num, _):
782             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
783
784         # Security groups
785
786         # Default is "global group"
787
788         m = Message()
789         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
790         m["groupType"] = MessageElement(
791           str(GTYPE_SECURITY_GLOBAL_GROUP),
792           FLAG_MOD_REPLACE, "groupType")
793         ldb.modify(m)
794
795         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
796                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
797         self.assertTrue(len(res1) == 1)
798         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
799           ATYPE_SECURITY_GLOBAL_GROUP)
800
801         # Change to "local" (shouldn't work)
802
803         try:
804             m = Message()
805             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
806             m["groupType"] = MessageElement(
807               str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
808               FLAG_MOD_REPLACE, "groupType")
809             ldb.modify(m)
810             self.fail()
811         except LdbError, (num, _):
812             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
813
814         # Change to "universal"
815
816         m = Message()
817         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
818         m["groupType"] = MessageElement(
819          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
820           FLAG_MOD_REPLACE, "groupType")
821         ldb.modify(m)
822
823         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
824                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
825         self.assertTrue(len(res1) == 1)
826         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
827           ATYPE_SECURITY_UNIVERSAL_GROUP)
828
829         # Change back to "global"
830
831         m = Message()
832         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
833         m["groupType"] = MessageElement(
834           str(GTYPE_SECURITY_GLOBAL_GROUP),
835           FLAG_MOD_REPLACE, "groupType")
836         ldb.modify(m)
837
838         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
839                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
840         self.assertTrue(len(res1) == 1)
841         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
842           ATYPE_SECURITY_GLOBAL_GROUP)
843
844         # Change back to "universal"
845
846         m = Message()
847         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
848         m["groupType"] = MessageElement(
849          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
850           FLAG_MOD_REPLACE, "groupType")
851         ldb.modify(m)
852
853         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
854                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
855         self.assertTrue(len(res1) == 1)
856         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
857           ATYPE_SECURITY_UNIVERSAL_GROUP)
858
859         # Change to "local"
860
861         m = Message()
862         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
863         m["groupType"] = MessageElement(
864           str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
865           FLAG_MOD_REPLACE, "groupType")
866         ldb.modify(m)
867
868         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
869                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
870         self.assertTrue(len(res1) == 1)
871         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
872           ATYPE_SECURITY_LOCAL_GROUP)
873
874         # Change to "global" (shouldn't work)
875
876         try:
877             m = Message()
878             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
879             m["groupType"] = MessageElement(
880               str(GTYPE_SECURITY_GLOBAL_GROUP),
881               FLAG_MOD_REPLACE, "groupType")
882             ldb.modify(m)
883             self.fail()
884         except LdbError, (num, _):
885             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
886
887         # Change to "builtin local" (shouldn't work)
888
889         try:
890             m = Message()
891             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
892             m["groupType"] = MessageElement(
893               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
894               FLAG_MOD_REPLACE, "groupType")
895             ldb.modify(m)
896             self.fail()
897         except LdbError, (num, _):
898             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
899
900         m = Message()
901         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
902
903         # Change back to "universal"
904
905         m = Message()
906         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
907         m["groupType"] = MessageElement(
908          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
909           FLAG_MOD_REPLACE, "groupType")
910         ldb.modify(m)
911
912         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
913                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
914         self.assertTrue(len(res1) == 1)
915         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
916           ATYPE_SECURITY_UNIVERSAL_GROUP)
917
918         # Change to "builtin local" (shouldn't work)
919
920         try:
921             m = Message()
922             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
923             m["groupType"] = MessageElement(
924               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
925               FLAG_MOD_REPLACE, "groupType")
926             ldb.modify(m)
927             self.fail()
928         except LdbError, (num, _):
929             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
930
931         # Change back to "global"
932
933         m = Message()
934         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
935         m["groupType"] = MessageElement(
936           str(GTYPE_SECURITY_GLOBAL_GROUP),
937           FLAG_MOD_REPLACE, "groupType")
938         ldb.modify(m)
939
940         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
941                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
942         self.assertTrue(len(res1) == 1)
943         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
944           ATYPE_SECURITY_GLOBAL_GROUP)
945
946         # Change to "builtin local" (shouldn't work)
947
948         try:
949             m = Message()
950             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
951             m["groupType"] = MessageElement(
952               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
953               FLAG_MOD_REPLACE, "groupType")
954             ldb.modify(m)
955             self.fail()
956         except LdbError, (num, _):
957             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
958
959         # Distribution groups
960
961         # Default is "global group"
962
963         m = Message()
964         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
965         m["groupType"] = MessageElement(
966           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
967           FLAG_MOD_REPLACE, "groupType")
968         ldb.modify(m)
969
970         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
971                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
972         self.assertTrue(len(res1) == 1)
973         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
974           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
975
976         # Change to local (shouldn't work)
977
978         try:
979             m = Message()
980             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
981             m["groupType"] = MessageElement(
982               str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
983               FLAG_MOD_REPLACE, "groupType")
984             ldb.modify(m)
985             self.fail()
986         except LdbError, (num, _):
987             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
988
989         # Change to "universal"
990
991         m = Message()
992         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
993         m["groupType"] = MessageElement(
994          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
995           FLAG_MOD_REPLACE, "groupType")
996         ldb.modify(m)
997
998         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
999                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1000         self.assertTrue(len(res1) == 1)
1001         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1002           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1003
1004         # Change back to "global"
1005
1006         m = Message()
1007         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1008         m["groupType"] = MessageElement(
1009           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1010           FLAG_MOD_REPLACE, "groupType")
1011         ldb.modify(m)
1012
1013         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1014                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1015         self.assertTrue(len(res1) == 1)
1016         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1017           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1018
1019         # Change back to "universal"
1020
1021         m = Message()
1022         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1023         m["groupType"] = MessageElement(
1024          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1025           FLAG_MOD_REPLACE, "groupType")
1026         ldb.modify(m)
1027
1028         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1029                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1030         self.assertTrue(len(res1) == 1)
1031         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1032           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1033
1034         # Change to "local"
1035
1036         m = Message()
1037         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1038         m["groupType"] = MessageElement(
1039           str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1040           FLAG_MOD_REPLACE, "groupType")
1041         ldb.modify(m)
1042
1043         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1044                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1045         self.assertTrue(len(res1) == 1)
1046         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1047           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1048
1049         # Change to "global" (shouldn't work)
1050
1051         try:
1052             m = Message()
1053             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1054             m["groupType"] = MessageElement(
1055               str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1056               FLAG_MOD_REPLACE, "groupType")
1057             ldb.modify(m)
1058             self.fail()
1059         except LdbError, (num, _):
1060             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1061
1062         # Change back to "universal"
1063
1064         # Try to add invalid member to group 1 - should be denied
1065         m = Message()
1066         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1067         m["member"] = MessageElement(
1068           "cn=ldaptestuser3,cn=users," + self.base_dn,
1069           FLAG_MOD_ADD, "member")
1070         try:
1071             ldb.modify(m)
1072             self.fail()
1073         except LdbError, (num, _):
1074             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1075
1076         # Make group 2 secondary
1077         m = Message()
1078         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1079         m["groupType"] = MessageElement(
1080          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1081           FLAG_MOD_REPLACE, "groupType")
1082         ldb.modify(m)
1083
1084         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1085                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1086         self.assertTrue(len(res1) == 1)
1087         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1088           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1089
1090         # Change back to "global"
1091
1092         m = Message()
1093         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1094         m["groupType"] = MessageElement(
1095           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1096           FLAG_MOD_REPLACE, "groupType")
1097         ldb.modify(m)
1098
1099         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1100                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1101         self.assertTrue(len(res1) == 1)
1102         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1103           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1104
1105         # Both group types: this performs only random checks - all possibilities
1106         # would require too much code.
1107
1108         # Default is "global group"
1109
1110         m = Message()
1111         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1112         m["groupType"] = MessageElement(
1113           str(GTYPE_SECURITY_GLOBAL_GROUP),
1114           FLAG_MOD_REPLACE, "groupType")
1115         ldb.modify(m)
1116
1117         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1118                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1119         self.assertTrue(len(res1) == 1)
1120         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1121           ATYPE_SECURITY_GLOBAL_GROUP)
1122
1123         # Change to "local" (shouldn't work)
1124
1125         try:
1126             m = Message()
1127             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1128             m["groupType"] = MessageElement(
1129               str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1130               FLAG_MOD_REPLACE, "groupType")
1131             ldb.modify(m)
1132             self.fail()
1133         except LdbError, (num, _):
1134             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1135
1136         # Change to "universal"
1137
1138         m = Message()
1139         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1140         m["groupType"] = MessageElement(
1141          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1142           FLAG_MOD_REPLACE, "groupType")
1143         ldb.modify(m)
1144
1145         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1146                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1147         self.assertTrue(len(res1) == 1)
1148         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1149           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1150
1151         # Change back to "global"
1152
1153         m = Message()
1154         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1155         m["groupType"] = MessageElement(
1156           str(GTYPE_SECURITY_GLOBAL_GROUP),
1157           FLAG_MOD_REPLACE, "groupType")
1158         ldb.modify(m)
1159
1160         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1161                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1162         self.assertTrue(len(res1) == 1)
1163         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1164           ATYPE_SECURITY_GLOBAL_GROUP)
1165
1166         # Change back to "universal"
1167
1168         m = Message()
1169         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1170         m["groupType"] = MessageElement(
1171          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1172           FLAG_MOD_REPLACE, "groupType")
1173         ldb.modify(m)
1174
1175         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1176                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1177         self.assertTrue(len(res1) == 1)
1178         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1179           ATYPE_SECURITY_UNIVERSAL_GROUP)
1180
1181         # Change to "local"
1182
1183         m = Message()
1184         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1185         m["groupType"] = MessageElement(
1186           str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1187           FLAG_MOD_REPLACE, "groupType")
1188         ldb.modify(m)
1189
1190         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1191                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1192         self.assertTrue(len(res1) == 1)
1193         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1194           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1195
1196         # Change to "global" (shouldn't work)
1197
1198         try:
1199             m = Message()
1200             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1201             m["groupType"] = MessageElement(
1202               str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1203               FLAG_MOD_REPLACE, "groupType")
1204             ldb.modify(m)
1205             self.fail()
1206         except LdbError, (num, _):
1207             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1208
1209         # Change back to "universal"
1210
1211         m = Message()
1212         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1213         m["groupType"] = MessageElement(
1214          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1215           FLAG_MOD_REPLACE, "groupType")
1216         ldb.modify(m)
1217
1218         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1219                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1220         self.assertTrue(len(res1) == 1)
1221         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1222           ATYPE_SECURITY_UNIVERSAL_GROUP)
1223
1224         # Change back to "global"
1225
1226         m = Message()
1227         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1228         m["groupType"] = MessageElement(
1229           str(GTYPE_SECURITY_GLOBAL_GROUP),
1230           FLAG_MOD_REPLACE, "groupType")
1231         ldb.modify(m)
1232
1233         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1234                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1235         self.assertTrue(len(res1) == 1)
1236         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1237           ATYPE_SECURITY_GLOBAL_GROUP)
1238
1239         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1240
1241     def test_userAccountControl(self):
1242         """Test the userAccountControl behaviour"""
1243         print "Testing userAccountControl behaviour\n"
1244
1245         # With a user object
1246
1247         # Add operation
1248
1249         # As user you can only set a normal account.
1250         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1251         # password yet.
1252         # With SYSTEM rights you can set a interdomain trust account.
1253
1254         # Invalid attribute
1255         try:
1256             ldb.add({
1257                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1258                 "objectclass": ["user", "person"],
1259                 "userAccountControl": "0"})
1260             self.fail()
1261         except LdbError, (num, _):
1262             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1263         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1264
1265 # This has to wait until s4 supports it (needs a password module change)
1266 #        try:
1267 #            ldb.add({
1268 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1269 #                "objectclass": ["user", "person"],
1270 #                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1271 #            self.fail()
1272 #        except LdbError, (num, _):
1273 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1274 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1275
1276         ldb.add({
1277             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1278             "objectclass": ["user", "person"],
1279             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1280
1281         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1282                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1283         self.assertTrue(len(res1) == 1)
1284         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1285           ATYPE_NORMAL_ACCOUNT)
1286         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1287
1288         try:
1289             ldb.add({
1290                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1291                 "objectclass": ["user", "person"],
1292                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1293             self.fail()
1294         except LdbError, (num, _):
1295             self.assertEquals(num, ERR_OTHER)
1296         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1297
1298 # This isn't supported yet in s4
1299 #        try:
1300 #            ldb.add({
1301 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1302 #                "objectclass": ["user", "person"],
1303 #                "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1304 #            self.fail()
1305 #        except LdbError, (num, _):
1306 #            self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1307 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1308 #
1309 #        try:
1310 #            ldb.add({
1311 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1312 #                "objectclass": ["user", "person"],
1313 #                "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1314 #        except LdbError, (num, _):
1315 #            self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1316 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1317
1318 # This isn't supported yet in s4 - needs ACL module adaption
1319 #        try:
1320 #            ldb.add({
1321 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1322 #                "objectclass": ["user", "person"],
1323 #                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1324 #            self.fail()
1325 #        except LdbError, (num, _):
1326 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1327 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1328
1329         # Modify operation
1330
1331         ldb.add({
1332             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1333             "objectclass": ["user", "person"]})
1334
1335         # After creation we should have a normal account
1336         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1337                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1338         self.assertTrue(len(res1) == 1)
1339         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1340           ATYPE_NORMAL_ACCOUNT)
1341
1342         # As user you can only switch from a normal account to a workstation
1343         # trust account and back.
1344         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1345         # password yet.
1346         # With SYSTEM rights you can switch to a interdomain trust account.
1347
1348         # Invalid attribute
1349         try:
1350             m = Message()
1351             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1352             m["userAccountControl"] = MessageElement("0",
1353               FLAG_MOD_REPLACE, "userAccountControl")
1354             ldb.modify(m)
1355         except LdbError, (num, _):
1356             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1357
1358 # This has to wait until s4 supports it (needs a password module change)
1359 #        try:
1360 #            m = Message()
1361 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1362 #            m["userAccountControl"] = MessageElement(
1363 #              str(UF_NORMAL_ACCOUNT),
1364 #              FLAG_MOD_REPLACE, "userAccountControl")
1365 #            ldb.modify(m)
1366 #        except LdbError, (num, _):
1367 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1368
1369         m = Message()
1370         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1371         m["userAccountControl"] = MessageElement(
1372           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1373           FLAG_MOD_REPLACE, "userAccountControl")
1374         ldb.modify(m)
1375
1376         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1377                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1378         self.assertTrue(len(res1) == 1)
1379         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1380           ATYPE_NORMAL_ACCOUNT)
1381
1382         try:
1383             m = Message()
1384             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1385             m["userAccountControl"] = MessageElement(
1386               str(UF_TEMP_DUPLICATE_ACCOUNT),
1387               FLAG_MOD_REPLACE, "userAccountControl")
1388             ldb.modify(m)
1389             self.fail()
1390         except LdbError, (num, _):
1391             self.assertEquals(num, ERR_OTHER)
1392
1393 # This isn't supported yet in s4
1394 #        try:
1395 #            m = Message()
1396 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1397 #            m["userAccountControl"] = MessageElement(
1398 #              str(UF_SERVER_TRUST_ACCOUNT),
1399 #              FLAG_MOD_REPLACE, "userAccountControl")
1400 #            ldb.modify(m)
1401 #            self.fail()
1402 #        except LdbError, (num, _):
1403 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1404
1405         m = Message()
1406         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1407         m["userAccountControl"] = MessageElement(
1408           str(UF_WORKSTATION_TRUST_ACCOUNT),
1409           FLAG_MOD_REPLACE, "userAccountControl")
1410         ldb.modify(m)
1411
1412         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1413                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1414         self.assertTrue(len(res1) == 1)
1415         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1416           ATYPE_WORKSTATION_TRUST)
1417
1418         m = Message()
1419         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1420         m["userAccountControl"] = MessageElement(
1421           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1422           FLAG_MOD_REPLACE, "userAccountControl")
1423         ldb.modify(m)
1424
1425         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1426                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1427         self.assertTrue(len(res1) == 1)
1428         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1429           ATYPE_NORMAL_ACCOUNT)
1430
1431 # This isn't supported yet in s4 - needs ACL module adaption
1432 #        try:
1433 #            m = Message()
1434 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1435 #            m["userAccountControl"] = MessageElement(
1436 #              str(UF_INTERDOMAIN_TRUST_ACCOUNT),
1437 #              FLAG_MOD_REPLACE, "userAccountControl")
1438 #            ldb.modify(m)
1439 #            self.fail()
1440 #        except LdbError, (num, _):
1441 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1442
1443         # With a computer object
1444
1445         # Add operation
1446
1447         # As computer you can set a normal account and a server trust account.
1448         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1449         # password yet.
1450         # With SYSTEM rights you can set a interdomain trust account.
1451
1452         # Invalid attribute
1453         try:
1454             ldb.add({
1455                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1456                 "objectclass": ["computer"],
1457                 "userAccountControl": "0"})
1458             self.fail()
1459         except LdbError, (num, _):
1460             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1461         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1462
1463 # This has to wait until s4 supports it (needs a password module change)
1464 #        try:
1465 #            ldb.add({
1466 #                "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1467 #                "objectclass": ["computer"],
1468 #                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1469 #            self.fail()
1470 #        except LdbError, (num, _):
1471 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1472 #        self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1473
1474         ldb.add({
1475             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1476             "objectclass": ["computer"],
1477             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1478
1479         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1480                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1481         self.assertTrue(len(res1) == 1)
1482         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1483           ATYPE_NORMAL_ACCOUNT)
1484         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1485
1486         try:
1487             ldb.add({
1488                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1489                 "objectclass": ["computer"],
1490                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1491             self.fail()
1492         except LdbError, (num, _):
1493             self.assertEquals(num, ERR_OTHER)
1494         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1495
1496         ldb.add({
1497             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1498             "objectclass": ["computer"],
1499             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1500
1501         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1502                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1503         self.assertTrue(len(res1) == 1)
1504         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1505           ATYPE_WORKSTATION_TRUST)
1506         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1507
1508         try:
1509             ldb.add({
1510                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1511                 "objectclass": ["computer"],
1512                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1513         except LdbError, (num, _):
1514             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1515         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1516
1517 # This isn't supported yet in s4 - needs ACL module adaption
1518 #        try:
1519 #            ldb.add({
1520 #                "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1521 #                "objectclass": ["computer"],
1522 #                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1523 #            self.fail()
1524 #        except LdbError, (num, _):
1525 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1526 #        self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1527
1528         # Modify operation
1529
1530         ldb.add({
1531             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1532             "objectclass": ["computer"]})
1533
1534         # After creation we should have a normal account
1535         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1536                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1537         self.assertTrue(len(res1) == 1)
1538         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1539           ATYPE_NORMAL_ACCOUNT)
1540
1541         # As computer you can switch from a normal account to a workstation
1542         # or server trust account and back (also swapping between trust
1543         # accounts is allowed).
1544         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1545         # password yet.
1546         # With SYSTEM rights you can switch to a interdomain trust account.
1547
1548         # Invalid attribute
1549         try:
1550             m = Message()
1551             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1552             m["userAccountControl"] = MessageElement("0",
1553               FLAG_MOD_REPLACE, "userAccountControl")
1554             ldb.modify(m)
1555         except LdbError, (num, _):
1556             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1557
1558 # This has to wait until s4 supports it (needs a password module change)
1559 #        try:
1560 #            m = Message()
1561 #            m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1562 #            m["userAccountControl"] = MessageElement(
1563 #              str(UF_NORMAL_ACCOUNT),
1564 #              FLAG_MOD_REPLACE, "userAccountControl")
1565 #            ldb.modify(m)
1566 #        except LdbError, (num, _):
1567 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1568
1569         m = Message()
1570         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1571         m["userAccountControl"] = MessageElement(
1572           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1573           FLAG_MOD_REPLACE, "userAccountControl")
1574         ldb.modify(m)
1575
1576         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1577                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1578         self.assertTrue(len(res1) == 1)
1579         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1580           ATYPE_NORMAL_ACCOUNT)
1581
1582         try:
1583             m = Message()
1584             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1585             m["userAccountControl"] = MessageElement(
1586               str(UF_TEMP_DUPLICATE_ACCOUNT),
1587               FLAG_MOD_REPLACE, "userAccountControl")
1588             ldb.modify(m)
1589             self.fail()
1590         except LdbError, (num, _):
1591             self.assertEquals(num, ERR_OTHER)
1592
1593         m = Message()
1594         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1595         m["userAccountControl"] = MessageElement(
1596           str(UF_SERVER_TRUST_ACCOUNT),
1597           FLAG_MOD_REPLACE, "userAccountControl")
1598         ldb.modify(m)
1599
1600         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1601                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1602         self.assertTrue(len(res1) == 1)
1603         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1604           ATYPE_WORKSTATION_TRUST)
1605
1606         m = Message()
1607         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1608         m["userAccountControl"] = MessageElement(
1609           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1610           FLAG_MOD_REPLACE, "userAccountControl")
1611         ldb.modify(m)
1612
1613         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1614                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1615         self.assertTrue(len(res1) == 1)
1616         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1617           ATYPE_NORMAL_ACCOUNT)
1618
1619         m = Message()
1620         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1621         m["userAccountControl"] = MessageElement(
1622           str(UF_WORKSTATION_TRUST_ACCOUNT),
1623           FLAG_MOD_REPLACE, "userAccountControl")
1624         ldb.modify(m)
1625
1626         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1627                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1628         self.assertTrue(len(res1) == 1)
1629         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1630           ATYPE_WORKSTATION_TRUST)
1631
1632         m = Message()
1633         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1634         m["userAccountControl"] = MessageElement(
1635           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1636           FLAG_MOD_REPLACE, "userAccountControl")
1637         ldb.modify(m)
1638
1639         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1640                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1641         self.assertTrue(len(res1) == 1)
1642         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1643           ATYPE_NORMAL_ACCOUNT)
1644
1645         m = Message()
1646         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1647         m["userAccountControl"] = MessageElement(
1648           str(UF_SERVER_TRUST_ACCOUNT),
1649           FLAG_MOD_REPLACE, "userAccountControl")
1650         ldb.modify(m)
1651
1652         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1653                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1654         self.assertTrue(len(res1) == 1)
1655         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1656           ATYPE_WORKSTATION_TRUST)
1657
1658         m = Message()
1659         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1660         m["userAccountControl"] = MessageElement(
1661           str(UF_WORKSTATION_TRUST_ACCOUNT),
1662           FLAG_MOD_REPLACE, "userAccountControl")
1663         ldb.modify(m)
1664
1665         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1666                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1667         self.assertTrue(len(res1) == 1)
1668         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1669           ATYPE_WORKSTATION_TRUST)
1670
1671 # This isn't supported yet in s4 - needs ACL module adaption
1672 #        try:
1673 #            m = Message()
1674 #            m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1675 #            m["userAccountControl"] = MessageElement(
1676 #              str(UF_INTERDOMAIN_TRUST_ACCOUNT),
1677 #              FLAG_MOD_REPLACE, "userAccountControl")
1678 #            ldb.modify(m)
1679 #            self.fail()
1680 #        except LdbError, (num, _):
1681 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1682
1683         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1684         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1685
1686 if not "://" in host:
1687     if os.path.isfile(host):
1688         host = "tdb://%s" % host
1689     else:
1690         host = "ldap://%s" % host
1691
1692 ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp)
1693 if not "tdb://" in host:
1694     gc_ldb = Ldb("%s:3268" % host, credentials=creds,
1695                  session_info=system_session(), lp=lp)
1696 else:
1697     gc_ldb = None
1698
1699 runner = SubunitTestRunner()
1700 rc = 0
1701 if not runner.run(unittest.makeSuite(SamTests)).wasSuccessful():
1702     rc = 1
1703 sys.exit(rc)