s4:sam.py - add a test for the "dNSHostName" - "servicePrincipalName" update mechanism
[kai/samba.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=ldaptestuser2,cn=users," + self.base_dn)
100         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
101         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
102         self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
103
104     def test_users_groups(self):
105         """This tests the SAM users and groups behaviour"""
106         print "Testing users and groups behaviour\n"
107
108         ldb.add({
109             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
110             "objectclass": "group"})
111
112         ldb.add({
113             "dn": "cn=ldaptestgroup2,cn=users," + self.base_dn,
114             "objectclass": "group"})
115
116         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
117                           scope=SCOPE_BASE, attrs=["objectSID"])
118         self.assertTrue(len(res1) == 1)
119         group_rid_1 = security.dom_sid(ldb.schema_format_value("objectSID",
120           res1[0]["objectSID"][0])).split()[1]
121
122         res1 = ldb.search("cn=ldaptestgroup2,cn=users," + self.base_dn,
123                           scope=SCOPE_BASE, attrs=["objectSID"])
124         self.assertTrue(len(res1) == 1)
125         group_rid_2 = security.dom_sid(ldb.schema_format_value("objectSID",
126           res1[0]["objectSID"][0])).split()[1]
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", "person"],
133                 "primaryGroupID": "0"})
134             self.fail()
135         except LdbError, (num, _):
136             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
137         self.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", "person"],
144                 "primaryGroupID": str(group_rid_1)})
145             self.fail()
146         except LdbError, (num, _):
147             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
148         self.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", "person"]})
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         self.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", "person"],
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         self.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         self.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         self.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         self.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", "person"]})
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         self.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         self.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", "person"]})
316
317         # We should be able to reset our actual primary group
318         m = Message()
319         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
320         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_USERS), FLAG_MOD_REPLACE,
321           "primaryGroupID")
322         ldb.modify(m)
323
324         # Try to add invalid primary group
325         m = Message()
326         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
327         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
328           "primaryGroupID")
329         try:
330             ldb.modify(m)
331             self.fail()
332         except LdbError, (num, _):
333             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
334
335         # Try to make group 1 primary - should be denied since it is not yet
336         # secondary
337         m = Message()
338         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
339         m["primaryGroupID"] = MessageElement(str(group_rid_1),
340           FLAG_MOD_REPLACE, "primaryGroupID")
341         try:
342             ldb.modify(m)
343             self.fail()
344         except LdbError, (num, _):
345             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
346
347         # Make group 1 secondary
348         m = Message()
349         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
350         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
351                                      FLAG_MOD_REPLACE, "member")
352         ldb.modify(m)
353
354         # Make group 1 primary
355         m = Message()
356         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
357         m["primaryGroupID"] = MessageElement(str(group_rid_1),
358           FLAG_MOD_REPLACE, "primaryGroupID")
359         ldb.modify(m)
360
361         # Try to delete group 1 - should be denied
362         try:
363             ldb.delete("cn=ldaptestgroup,cn=users," + self.base_dn)
364             self.fail()
365         except LdbError, (num, _):
366             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
367
368         # Try to add group 1 also as secondary - should be denied
369         m = Message()
370         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
371         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
372                                      FLAG_MOD_ADD, "member")
373         try:
374             ldb.modify(m)
375             self.fail()
376         except LdbError, (num, _):
377             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
378
379         # Try to add invalid member to group 1 - should be denied
380         m = Message()
381         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
382         m["member"] = MessageElement(
383           "cn=ldaptestuser3,cn=users," + self.base_dn,
384           FLAG_MOD_ADD, "member")
385         try:
386             ldb.modify(m)
387             self.fail()
388         except LdbError, (num, _):
389             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
390
391         # Make group 2 secondary
392         m = Message()
393         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
394         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
395                                      FLAG_MOD_ADD, "member")
396         ldb.modify(m)
397
398         # Swap the groups
399         m = Message()
400         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
401         m["primaryGroupID"] = MessageElement(str(group_rid_2),
402           FLAG_MOD_REPLACE, "primaryGroupID")
403         ldb.modify(m)
404
405         # Swap the groups (does not really make sense but does the same)
406         m = Message()
407         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
408         m["primaryGroupID"] = MessageElement(str(group_rid_1),
409           FLAG_MOD_REPLACE, "primaryGroupID")
410         m["primaryGroupID"] = MessageElement(str(group_rid_2),
411           FLAG_MOD_REPLACE, "primaryGroupID")
412         ldb.modify(m)
413
414         # Old primary group should contain a "member" attribute for the user,
415         # the new shouldn't contain anymore one
416         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
417                           scope=SCOPE_BASE, attrs=["member"])
418         self.assertTrue(len(res1) == 1)
419         self.assertTrue(len(res1[0]["member"]) == 1)
420         self.assertEquals(res1[0]["member"][0].lower(),
421           ("cn=ldaptestuser,cn=users," + self.base_dn).lower())
422
423         res1 = ldb.search("cn=ldaptestgroup2, cn=users," + self.base_dn,
424                           scope=SCOPE_BASE, attrs=["member"])
425         self.assertTrue(len(res1) == 1)
426         self.assertFalse("member" in res1[0])
427
428         # Primary group member
429         m = Message()
430         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
431         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
432                                      FLAG_MOD_DELETE, "member")
433         try:
434             ldb.modify(m)
435             self.fail()
436         except LdbError, (num, _):
437             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
438
439         # Delete invalid group member
440         m = Message()
441         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
442         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
443                                      FLAG_MOD_DELETE, "member")
444         try:
445             ldb.modify(m)
446             self.fail()
447         except LdbError, (num, _):
448             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
449
450         # Also this should be denied
451         try:
452             ldb.add({
453               "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
454               "objectclass": ["user", "person"],
455               "primaryGroupID": "0"})
456             self.fail()
457         except LdbError, (num, _):
458             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
459
460         # Recreate user accounts
461
462         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
463
464         ldb.add({
465             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
466             "objectclass": ["user", "person"]})
467
468         ldb.add({
469             "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
470             "objectclass": ["user", "person"]})
471
472         m = Message()
473         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
474         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
475                                      FLAG_MOD_ADD, "member")
476         ldb.modify(m)
477
478         # Already added
479         m = Message()
480         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
481         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
482                                      FLAG_MOD_ADD, "member")
483         try:
484             ldb.modify(m)
485             self.fail()
486         except LdbError, (num, _):
487             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
488
489         # Invalid member
490         m = Message()
491         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
492         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
493                                      FLAG_MOD_REPLACE, "member")
494         try:
495             ldb.modify(m)
496             self.fail()
497         except LdbError, (num, _):
498             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
499
500         # Invalid member
501         m = Message()
502         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
503         m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn,
504                                       "cn=ldaptestuser1,cn=users," + self.base_dn],
505                                      FLAG_MOD_REPLACE, "member")
506         try:
507             ldb.modify(m)
508             self.fail()
509         except LdbError, (num, _):
510             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
511
512         # Invalid member
513         m = Message()
514         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
515         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
516                                      FLAG_MOD_REPLACE, "member")
517         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
518                                      FLAG_MOD_ADD, "member")
519         try:
520             ldb.modify(m)
521             self.fail()
522         except LdbError, (num, _):
523             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
524
525         m = Message()
526         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
527         m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn,
528                                       "cn=ldaptestuser2,cn=users," + self.base_dn],
529                                      FLAG_MOD_REPLACE, "member")
530         ldb.modify(m)
531
532         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
533         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
534         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
535         self.delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
536
537     def test_sam_attributes(self):
538         """Test the behaviour of special attributes of SAM objects"""
539         print "Testing the behaviour of special attributes of SAM objects\n"""
540
541         ldb.add({
542             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
543             "objectclass": ["user", "person"]})
544         ldb.add({
545             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
546             "objectclass": "group"})
547
548         m = Message()
549         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
550         m["groupType"] = MessageElement("0", FLAG_MOD_ADD,
551           "groupType")
552         try:
553             ldb.modify(m)
554             self.fail()
555         except LdbError, (num, _):
556             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
557
558         m = Message()
559         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
560         m["groupType"] = MessageElement([], FLAG_MOD_DELETE,
561           "groupType")
562         try:
563             ldb.modify(m)
564             self.fail()
565         except LdbError, (num, _):
566             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
567
568         m = Message()
569         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
570         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_ADD,
571           "primaryGroupID")
572         try:
573             ldb.modify(m)
574             self.fail()
575         except LdbError, (num, _):
576             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
577
578         m = Message()
579         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
580         m["primaryGroupID"] = MessageElement([], FLAG_MOD_DELETE,
581           "primaryGroupID")
582         try:
583             ldb.modify(m)
584             self.fail()
585         except LdbError, (num, _):
586             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
587
588         m = Message()
589         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
590         m["userAccountControl"] = MessageElement("0", FLAG_MOD_ADD,
591           "userAccountControl")
592         try:
593             ldb.modify(m)
594             self.fail()
595         except LdbError, (num, _):
596             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
597
598         m = Message()
599         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
600         m["userAccountControl"] = MessageElement([], FLAG_MOD_DELETE,
601           "userAccountControl")
602         try:
603             ldb.modify(m)
604             self.fail()
605         except LdbError, (num, _):
606             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
607
608         m = Message()
609         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
610         m["sAMAccountType"] = MessageElement("0", FLAG_MOD_ADD,
611           "sAMAccountType")
612         try:
613             ldb.modify(m)
614             self.fail()
615         except LdbError, (num, _):
616             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
617
618         m = Message()
619         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
620         m["sAMAccountType"] = MessageElement([], FLAG_MOD_REPLACE,
621           "sAMAccountType")
622         try:
623             ldb.modify(m)
624             self.fail()
625         except LdbError, (num, _):
626             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
627
628         m = Message()
629         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
630         m["sAMAccountType"] = MessageElement([], FLAG_MOD_DELETE,
631           "sAMAccountType")
632         try:
633             ldb.modify(m)
634             self.fail()
635         except LdbError, (num, _):
636             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
637
638         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
639         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
640
641     def test_primary_group_token_constructed(self):
642         """Test the primary group token behaviour (hidden-generated-readonly attribute on groups) and some other constructed attributes"""
643         print "Testing primary group token behaviour and other constructed attributes\n"
644
645         try:
646             ldb.add({
647                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
648                 "objectclass": "group",
649                 "primaryGroupToken": "100"})
650             self.fail()
651         except LdbError, (num, _):
652             self.assertEquals(num, ERR_UNDEFINED_ATTRIBUTE_TYPE)
653         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
654
655         ldb.add({
656             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
657             "objectclass": ["user", "person"]})
658
659         ldb.add({
660             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
661             "objectclass": "group"})
662
663         # Testing for one invalid, and one valid operational attribute, but also the things they are built from
664         res1 = ldb.search(self.base_dn,
665                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName", "objectClass", "objectSid"])
666         self.assertTrue(len(res1) == 1)
667         self.assertFalse("primaryGroupToken" in res1[0])
668         self.assertTrue("canonicalName" in res1[0])
669         self.assertTrue("objectClass" in res1[0])
670         self.assertTrue("objectSid" in res1[0])
671
672         res1 = ldb.search(self.base_dn,
673                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName"])
674         self.assertTrue(len(res1) == 1)
675         self.assertFalse("primaryGroupToken" in res1[0])
676         self.assertFalse("objectSid" in res1[0])
677         self.assertFalse("objectClass" in res1[0])
678         self.assertTrue("canonicalName" in res1[0])
679
680         res1 = ldb.search("cn=users," + self.base_dn,
681                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
682         self.assertTrue(len(res1) == 1)
683         self.assertFalse("primaryGroupToken" in res1[0])
684
685         res1 = ldb.search("cn=ldaptestuser, cn=users," + self.base_dn,
686                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
687         self.assertTrue(len(res1) == 1)
688         self.assertFalse("primaryGroupToken" in res1[0])
689
690         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
691                           scope=SCOPE_BASE)
692         self.assertTrue(len(res1) == 1)
693         self.assertFalse("primaryGroupToken" in res1[0])
694
695         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
696                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "objectSID"])
697         self.assertTrue(len(res1) == 1)
698         primary_group_token = int(res1[0]["primaryGroupToken"][0])
699
700         rid = security.dom_sid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0])).split()[1]
701         self.assertEquals(primary_group_token, rid)
702
703         m = Message()
704         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
705         m["primaryGroupToken"] = "100"
706         try:
707             ldb.modify(m)
708             self.fail()
709         except LdbError, (num, _):
710             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
711
712         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
713         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
714
715     def test_tokenGroups(self):
716         """Test the tokenGroups behaviour (hidden-generated-readonly attribute on SAM objects)"""
717         print "Testing tokenGroups behaviour\n"
718
719         # The domain object shouldn't contain any "tokenGroups" entry
720         res = ldb.search(self.base_dn, scope=SCOPE_BASE, attrs=["tokenGroups"])
721         self.assertTrue(len(res) == 1)
722         self.assertFalse("tokenGroups" in res[0])
723
724         # The domain administrator should contain "tokenGroups" entries
725         # (the exact number depends on the domain/forest function level and the
726         # DC software versions)
727         res = ldb.search("cn=Administrator,cn=Users," + self.base_dn,
728                          scope=SCOPE_BASE, attrs=["tokenGroups"])
729         self.assertTrue(len(res) == 1)
730         self.assertTrue("tokenGroups" in res[0])
731
732         ldb.add({
733             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
734             "objectclass": ["user", "person"]})
735
736         # This testuser should contain at least two "tokenGroups" entries
737         # (exactly two on an unmodified "Domain Users" and "Users" group)
738         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
739                          scope=SCOPE_BASE, attrs=["tokenGroups"])
740         self.assertTrue(len(res) == 1)
741         self.assertTrue(len(res[0]["tokenGroups"]) >= 2)
742
743         # one entry which we need to find should point to domains "Domain Users"
744         # group and another entry should point to the builtin "Users"group
745         domain_users_group_found = False
746         users_group_found = False
747         for sid in res[0]["tokenGroups"]:
748             rid = security.dom_sid(ldb.schema_format_value("objectSID", sid)).split()[1]
749             if rid == 513:
750                 domain_users_group_found = True
751             if rid == 545:
752                 users_group_found = True
753
754         self.assertTrue(domain_users_group_found)
755         self.assertTrue(users_group_found)
756
757         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
758
759     def test_groupType(self):
760         """Test the groupType behaviour"""
761         print "Testing groupType behaviour\n"
762
763         # You can never create or change to a
764         # "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP"
765
766         # Add operation
767
768         # Invalid attribute
769         try:
770             ldb.add({
771                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
772                 "objectclass": "group",
773                 "groupType": "0"})
774             self.fail()
775         except LdbError, (num, _):
776             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
777         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
778
779         try:
780             ldb.add({
781                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
782                 "objectclass": "group",
783                 "groupType": str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP)})
784             self.fail()
785         except LdbError, (num, _):
786             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
787         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
788
789         ldb.add({
790             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
791             "objectclass": "group",
792             "groupType": str(GTYPE_SECURITY_GLOBAL_GROUP)})
793
794         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
795                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
796         self.assertTrue(len(res1) == 1)
797         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
798           ATYPE_SECURITY_GLOBAL_GROUP)
799         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
800
801         ldb.add({
802             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
803             "objectclass": "group",
804             "groupType": str(GTYPE_SECURITY_UNIVERSAL_GROUP)})
805
806         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
807                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
808         self.assertTrue(len(res1) == 1)
809         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
810           ATYPE_SECURITY_UNIVERSAL_GROUP)
811         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
812
813         ldb.add({
814             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
815             "objectclass": "group",
816             "groupType": str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)})
817
818         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
819                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
820         self.assertTrue(len(res1) == 1)
821         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
822           ATYPE_SECURITY_LOCAL_GROUP)
823         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
824
825         ldb.add({
826             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
827             "objectclass": "group",
828             "groupType": str(GTYPE_DISTRIBUTION_GLOBAL_GROUP)})
829
830         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
831                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
832         self.assertTrue(len(res1) == 1)
833         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
834           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
835         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
836
837         ldb.add({
838             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
839             "objectclass": "group",
840             "groupType": str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP)})
841
842         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
843                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
844         self.assertTrue(len(res1) == 1)
845         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
846           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
847         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
848
849         ldb.add({
850             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
851             "objectclass": "group",
852             "groupType": str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)})
853
854         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
855                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
856         self.assertTrue(len(res1) == 1)
857         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
858           ATYPE_DISTRIBUTION_LOCAL_GROUP)
859         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
860
861         # Modify operation
862
863         ldb.add({
864             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
865             "objectclass": "group"})
866
867         # We can change in this direction: global <-> universal <-> local
868         # On each step also the group type itself (security/distribution) is
869         # variable.
870
871         # After creation we should have a "security global group"
872         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
873                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
874         self.assertTrue(len(res1) == 1)
875         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
876           ATYPE_SECURITY_GLOBAL_GROUP)
877
878         # Invalid attribute
879         try:
880             m = Message()
881             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
882             m["groupType"] = MessageElement("0",
883               FLAG_MOD_REPLACE, "groupType")
884             ldb.modify(m)
885             self.fail()
886         except LdbError, (num, _):
887             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
888
889         # Security groups
890
891         # Default is "global group"
892
893         m = Message()
894         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
895         m["groupType"] = MessageElement(
896           str(GTYPE_SECURITY_GLOBAL_GROUP),
897           FLAG_MOD_REPLACE, "groupType")
898         ldb.modify(m)
899
900         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
901                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
902         self.assertTrue(len(res1) == 1)
903         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
904           ATYPE_SECURITY_GLOBAL_GROUP)
905
906         # Change to "local" (shouldn't work)
907
908         try:
909             m = Message()
910             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
911             m["groupType"] = MessageElement(
912               str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
913               FLAG_MOD_REPLACE, "groupType")
914             ldb.modify(m)
915             self.fail()
916         except LdbError, (num, _):
917             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
918
919         # Change to "universal"
920
921         m = Message()
922         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
923         m["groupType"] = MessageElement(
924          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
925           FLAG_MOD_REPLACE, "groupType")
926         ldb.modify(m)
927
928         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
929                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
930         self.assertTrue(len(res1) == 1)
931         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
932           ATYPE_SECURITY_UNIVERSAL_GROUP)
933
934         # Change back to "global"
935
936         m = Message()
937         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
938         m["groupType"] = MessageElement(
939           str(GTYPE_SECURITY_GLOBAL_GROUP),
940           FLAG_MOD_REPLACE, "groupType")
941         ldb.modify(m)
942
943         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
944                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
945         self.assertTrue(len(res1) == 1)
946         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
947           ATYPE_SECURITY_GLOBAL_GROUP)
948
949         # Change back to "universal"
950
951         m = Message()
952         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
953         m["groupType"] = MessageElement(
954          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
955           FLAG_MOD_REPLACE, "groupType")
956         ldb.modify(m)
957
958         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
959                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
960         self.assertTrue(len(res1) == 1)
961         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
962           ATYPE_SECURITY_UNIVERSAL_GROUP)
963
964         # Change to "local"
965
966         m = Message()
967         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
968         m["groupType"] = MessageElement(
969           str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
970           FLAG_MOD_REPLACE, "groupType")
971         ldb.modify(m)
972
973         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
974                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
975         self.assertTrue(len(res1) == 1)
976         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
977           ATYPE_SECURITY_LOCAL_GROUP)
978
979         # Change to "global" (shouldn't work)
980
981         try:
982             m = Message()
983             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
984             m["groupType"] = MessageElement(
985               str(GTYPE_SECURITY_GLOBAL_GROUP),
986               FLAG_MOD_REPLACE, "groupType")
987             ldb.modify(m)
988             self.fail()
989         except LdbError, (num, _):
990             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
991
992         # Change to "builtin local" (shouldn't work)
993
994         try:
995             m = Message()
996             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
997             m["groupType"] = MessageElement(
998               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
999               FLAG_MOD_REPLACE, "groupType")
1000             ldb.modify(m)
1001             self.fail()
1002         except LdbError, (num, _):
1003             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1004
1005         m = Message()
1006         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1007
1008         # Change back to "universal"
1009
1010         m = Message()
1011         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1012         m["groupType"] = MessageElement(
1013          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1014           FLAG_MOD_REPLACE, "groupType")
1015         ldb.modify(m)
1016
1017         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1018                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1019         self.assertTrue(len(res1) == 1)
1020         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1021           ATYPE_SECURITY_UNIVERSAL_GROUP)
1022
1023         # Change to "builtin local" (shouldn't work)
1024
1025         try:
1026             m = Message()
1027             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1028             m["groupType"] = MessageElement(
1029               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1030               FLAG_MOD_REPLACE, "groupType")
1031             ldb.modify(m)
1032             self.fail()
1033         except LdbError, (num, _):
1034             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1035
1036         # Change back to "global"
1037
1038         m = Message()
1039         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1040         m["groupType"] = MessageElement(
1041           str(GTYPE_SECURITY_GLOBAL_GROUP),
1042           FLAG_MOD_REPLACE, "groupType")
1043         ldb.modify(m)
1044
1045         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1046                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1047         self.assertTrue(len(res1) == 1)
1048         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1049           ATYPE_SECURITY_GLOBAL_GROUP)
1050
1051         # Change to "builtin local" (shouldn't work)
1052
1053         try:
1054             m = Message()
1055             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1056             m["groupType"] = MessageElement(
1057               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1058               FLAG_MOD_REPLACE, "groupType")
1059             ldb.modify(m)
1060             self.fail()
1061         except LdbError, (num, _):
1062             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1063
1064         # Distribution groups
1065
1066         # Default is "global group"
1067
1068         m = Message()
1069         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1070         m["groupType"] = MessageElement(
1071           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1072           FLAG_MOD_REPLACE, "groupType")
1073         ldb.modify(m)
1074
1075         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1076                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1077         self.assertTrue(len(res1) == 1)
1078         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1079           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1080
1081         # Change to local (shouldn't work)
1082
1083         try:
1084             m = Message()
1085             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1086             m["groupType"] = MessageElement(
1087               str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1088               FLAG_MOD_REPLACE, "groupType")
1089             ldb.modify(m)
1090             self.fail()
1091         except LdbError, (num, _):
1092             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1093
1094         # Change to "universal"
1095
1096         m = Message()
1097         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1098         m["groupType"] = MessageElement(
1099          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1100           FLAG_MOD_REPLACE, "groupType")
1101         ldb.modify(m)
1102
1103         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1104                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1105         self.assertTrue(len(res1) == 1)
1106         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1107           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1108
1109         # Change back to "global"
1110
1111         m = Message()
1112         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1113         m["groupType"] = MessageElement(
1114           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1115           FLAG_MOD_REPLACE, "groupType")
1116         ldb.modify(m)
1117
1118         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1119                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1120         self.assertTrue(len(res1) == 1)
1121         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1122           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1123
1124         # Change back to "universal"
1125
1126         m = Message()
1127         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1128         m["groupType"] = MessageElement(
1129          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1130           FLAG_MOD_REPLACE, "groupType")
1131         ldb.modify(m)
1132
1133         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1134                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1135         self.assertTrue(len(res1) == 1)
1136         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1137           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1138
1139         # Change to "local"
1140
1141         m = Message()
1142         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1143         m["groupType"] = MessageElement(
1144           str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1145           FLAG_MOD_REPLACE, "groupType")
1146         ldb.modify(m)
1147
1148         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1149                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1150         self.assertTrue(len(res1) == 1)
1151         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1152           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1153
1154         # Change to "global" (shouldn't work)
1155
1156         try:
1157             m = Message()
1158             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1159             m["groupType"] = MessageElement(
1160               str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1161               FLAG_MOD_REPLACE, "groupType")
1162             ldb.modify(m)
1163             self.fail()
1164         except LdbError, (num, _):
1165             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1166
1167         # Change back to "universal"
1168
1169         # Try to add invalid member to group 1 - should be denied
1170         m = Message()
1171         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1172         m["member"] = MessageElement(
1173           "cn=ldaptestuser3,cn=users," + self.base_dn,
1174           FLAG_MOD_ADD, "member")
1175         try:
1176             ldb.modify(m)
1177             self.fail()
1178         except LdbError, (num, _):
1179             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1180
1181         # Make group 2 secondary
1182         m = Message()
1183         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1184         m["groupType"] = MessageElement(
1185          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1186           FLAG_MOD_REPLACE, "groupType")
1187         ldb.modify(m)
1188
1189         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1190                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1191         self.assertTrue(len(res1) == 1)
1192         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1193           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1194
1195         # Change back to "global"
1196
1197         m = Message()
1198         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1199         m["groupType"] = MessageElement(
1200           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1201           FLAG_MOD_REPLACE, "groupType")
1202         ldb.modify(m)
1203
1204         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1205                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1206         self.assertTrue(len(res1) == 1)
1207         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1208           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1209
1210         # Both group types: this performs only random checks - all possibilities
1211         # would require too much code.
1212
1213         # Default is "global group"
1214
1215         m = Message()
1216         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1217         m["groupType"] = MessageElement(
1218           str(GTYPE_SECURITY_GLOBAL_GROUP),
1219           FLAG_MOD_REPLACE, "groupType")
1220         ldb.modify(m)
1221
1222         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1223                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1224         self.assertTrue(len(res1) == 1)
1225         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1226           ATYPE_SECURITY_GLOBAL_GROUP)
1227
1228         # Change to "local" (shouldn't work)
1229
1230         try:
1231             m = Message()
1232             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1233             m["groupType"] = MessageElement(
1234               str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1235               FLAG_MOD_REPLACE, "groupType")
1236             ldb.modify(m)
1237             self.fail()
1238         except LdbError, (num, _):
1239             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1240
1241         # Change to "universal"
1242
1243         m = Message()
1244         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1245         m["groupType"] = MessageElement(
1246          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1247           FLAG_MOD_REPLACE, "groupType")
1248         ldb.modify(m)
1249
1250         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1251                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1252         self.assertTrue(len(res1) == 1)
1253         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1254           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1255
1256         # Change back to "global"
1257
1258         m = Message()
1259         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1260         m["groupType"] = MessageElement(
1261           str(GTYPE_SECURITY_GLOBAL_GROUP),
1262           FLAG_MOD_REPLACE, "groupType")
1263         ldb.modify(m)
1264
1265         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1266                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1267         self.assertTrue(len(res1) == 1)
1268         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1269           ATYPE_SECURITY_GLOBAL_GROUP)
1270
1271         # Change back to "universal"
1272
1273         m = Message()
1274         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1275         m["groupType"] = MessageElement(
1276          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1277           FLAG_MOD_REPLACE, "groupType")
1278         ldb.modify(m)
1279
1280         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1281                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1282         self.assertTrue(len(res1) == 1)
1283         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1284           ATYPE_SECURITY_UNIVERSAL_GROUP)
1285
1286         # Change to "local"
1287
1288         m = Message()
1289         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1290         m["groupType"] = MessageElement(
1291           str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1292           FLAG_MOD_REPLACE, "groupType")
1293         ldb.modify(m)
1294
1295         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1296                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1297         self.assertTrue(len(res1) == 1)
1298         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1299           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1300
1301         # Change to "global" (shouldn't work)
1302
1303         try:
1304             m = Message()
1305             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1306             m["groupType"] = MessageElement(
1307               str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1308               FLAG_MOD_REPLACE, "groupType")
1309             ldb.modify(m)
1310             self.fail()
1311         except LdbError, (num, _):
1312             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1313
1314         # Change back to "universal"
1315
1316         m = Message()
1317         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1318         m["groupType"] = MessageElement(
1319          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1320           FLAG_MOD_REPLACE, "groupType")
1321         ldb.modify(m)
1322
1323         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1324                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1325         self.assertTrue(len(res1) == 1)
1326         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1327           ATYPE_SECURITY_UNIVERSAL_GROUP)
1328
1329         # Change back to "global"
1330
1331         m = Message()
1332         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1333         m["groupType"] = MessageElement(
1334           str(GTYPE_SECURITY_GLOBAL_GROUP),
1335           FLAG_MOD_REPLACE, "groupType")
1336         ldb.modify(m)
1337
1338         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1339                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1340         self.assertTrue(len(res1) == 1)
1341         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1342           ATYPE_SECURITY_GLOBAL_GROUP)
1343
1344         self.delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1345
1346     def test_userAccountControl(self):
1347         """Test the userAccountControl behaviour"""
1348         print "Testing userAccountControl behaviour\n"
1349
1350         # With a user object
1351
1352         # Add operation
1353
1354         # As user you can only set a normal account.
1355         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1356         # password yet.
1357         # With SYSTEM rights you can set a interdomain trust account.
1358
1359         # Invalid attribute
1360         try:
1361             ldb.add({
1362                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1363                 "objectclass": ["user", "person"],
1364                 "userAccountControl": "0"})
1365             self.fail()
1366         except LdbError, (num, _):
1367             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1368         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1369
1370 # This has to wait until s4 supports it (needs a password module change)
1371 #        try:
1372 #            ldb.add({
1373 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1374 #                "objectclass": ["user", "person"],
1375 #                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1376 #            self.fail()
1377 #        except LdbError, (num, _):
1378 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1379 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1380
1381         ldb.add({
1382             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1383             "objectclass": ["user", "person"],
1384             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1385
1386         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1387                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1388         self.assertTrue(len(res1) == 1)
1389         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1390           ATYPE_NORMAL_ACCOUNT)
1391         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1392
1393         try:
1394             ldb.add({
1395                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1396                 "objectclass": ["user", "person"],
1397                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1398             self.fail()
1399         except LdbError, (num, _):
1400             self.assertEquals(num, ERR_OTHER)
1401         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1402
1403 # This isn't supported yet in s4
1404 #        try:
1405 #            ldb.add({
1406 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1407 #                "objectclass": ["user", "person"],
1408 #                "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1409 #            self.fail()
1410 #        except LdbError, (num, _):
1411 #            self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1412 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1413 #
1414 #        try:
1415 #            ldb.add({
1416 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1417 #                "objectclass": ["user", "person"],
1418 #                "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1419 #        except LdbError, (num, _):
1420 #            self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1421 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1422
1423 # This isn't supported yet in s4 - needs ACL module adaption
1424 #        try:
1425 #            ldb.add({
1426 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1427 #                "objectclass": ["user", "person"],
1428 #                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1429 #            self.fail()
1430 #        except LdbError, (num, _):
1431 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1432 #        self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1433
1434         # Modify operation
1435
1436         ldb.add({
1437             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1438             "objectclass": ["user", "person"]})
1439
1440         # After creation we should have a normal account
1441         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1442                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1443         self.assertTrue(len(res1) == 1)
1444         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1445           ATYPE_NORMAL_ACCOUNT)
1446
1447         # As user you can only switch from a normal account to a workstation
1448         # trust account and back.
1449         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1450         # password yet.
1451         # With SYSTEM rights you can switch to a interdomain trust account.
1452
1453         # Invalid attribute
1454         try:
1455             m = Message()
1456             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1457             m["userAccountControl"] = MessageElement("0",
1458               FLAG_MOD_REPLACE, "userAccountControl")
1459             ldb.modify(m)
1460         except LdbError, (num, _):
1461             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1462
1463 # This has to wait until s4 supports it (needs a password module change)
1464 #        try:
1465 #            m = Message()
1466 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1467 #            m["userAccountControl"] = MessageElement(
1468 #              str(UF_NORMAL_ACCOUNT),
1469 #              FLAG_MOD_REPLACE, "userAccountControl")
1470 #            ldb.modify(m)
1471 #        except LdbError, (num, _):
1472 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1473
1474         m = Message()
1475         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1476         m["userAccountControl"] = MessageElement(
1477           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1478           FLAG_MOD_REPLACE, "userAccountControl")
1479         ldb.modify(m)
1480
1481         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1482                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1483         self.assertTrue(len(res1) == 1)
1484         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1485           ATYPE_NORMAL_ACCOUNT)
1486
1487         try:
1488             m = Message()
1489             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1490             m["userAccountControl"] = MessageElement(
1491               str(UF_TEMP_DUPLICATE_ACCOUNT),
1492               FLAG_MOD_REPLACE, "userAccountControl")
1493             ldb.modify(m)
1494             self.fail()
1495         except LdbError, (num, _):
1496             self.assertEquals(num, ERR_OTHER)
1497
1498 # This isn't supported yet in s4
1499 #        try:
1500 #            m = Message()
1501 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1502 #            m["userAccountControl"] = MessageElement(
1503 #              str(UF_SERVER_TRUST_ACCOUNT),
1504 #              FLAG_MOD_REPLACE, "userAccountControl")
1505 #            ldb.modify(m)
1506 #            self.fail()
1507 #        except LdbError, (num, _):
1508 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1509
1510         m = Message()
1511         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1512         m["userAccountControl"] = MessageElement(
1513           str(UF_WORKSTATION_TRUST_ACCOUNT),
1514           FLAG_MOD_REPLACE, "userAccountControl")
1515         ldb.modify(m)
1516
1517         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1518                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1519         self.assertTrue(len(res1) == 1)
1520         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1521           ATYPE_WORKSTATION_TRUST)
1522
1523         m = Message()
1524         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1525         m["userAccountControl"] = MessageElement(
1526           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1527           FLAG_MOD_REPLACE, "userAccountControl")
1528         ldb.modify(m)
1529
1530         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1531                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1532         self.assertTrue(len(res1) == 1)
1533         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1534           ATYPE_NORMAL_ACCOUNT)
1535
1536 # This isn't supported yet in s4 - needs ACL module adaption
1537 #        try:
1538 #            m = Message()
1539 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1540 #            m["userAccountControl"] = MessageElement(
1541 #              str(UF_INTERDOMAIN_TRUST_ACCOUNT),
1542 #              FLAG_MOD_REPLACE, "userAccountControl")
1543 #            ldb.modify(m)
1544 #            self.fail()
1545 #        except LdbError, (num, _):
1546 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1547
1548         # With a computer object
1549
1550         # Add operation
1551
1552         # As computer you can set a normal account and a server trust account.
1553         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1554         # password yet.
1555         # With SYSTEM rights you can set a interdomain trust account.
1556
1557         # Invalid attribute
1558         try:
1559             ldb.add({
1560                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1561                 "objectclass": ["computer"],
1562                 "userAccountControl": "0"})
1563             self.fail()
1564         except LdbError, (num, _):
1565             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1566         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1567
1568 # This has to wait until s4 supports it (needs a password module change)
1569 #        try:
1570 #            ldb.add({
1571 #                "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1572 #                "objectclass": ["computer"],
1573 #                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1574 #            self.fail()
1575 #        except LdbError, (num, _):
1576 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1577 #        self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1578
1579         ldb.add({
1580             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1581             "objectclass": ["computer"],
1582             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1583
1584         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1585                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1586         self.assertTrue(len(res1) == 1)
1587         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1588           ATYPE_NORMAL_ACCOUNT)
1589         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1590
1591         try:
1592             ldb.add({
1593                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1594                 "objectclass": ["computer"],
1595                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1596             self.fail()
1597         except LdbError, (num, _):
1598             self.assertEquals(num, ERR_OTHER)
1599         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1600
1601         ldb.add({
1602             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1603             "objectclass": ["computer"],
1604             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1605
1606         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1607                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1608         self.assertTrue(len(res1) == 1)
1609         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1610           ATYPE_WORKSTATION_TRUST)
1611         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1612
1613         try:
1614             ldb.add({
1615                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1616                 "objectclass": ["computer"],
1617                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1618         except LdbError, (num, _):
1619             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1620         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1621
1622 # This isn't supported yet in s4 - needs ACL module adaption
1623 #        try:
1624 #            ldb.add({
1625 #                "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1626 #                "objectclass": ["computer"],
1627 #                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1628 #            self.fail()
1629 #        except LdbError, (num, _):
1630 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1631 #        self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1632
1633         # Modify operation
1634
1635         ldb.add({
1636             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1637             "objectclass": ["computer"]})
1638
1639         # After creation we should have a normal account
1640         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1641                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1642         self.assertTrue(len(res1) == 1)
1643         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1644           ATYPE_NORMAL_ACCOUNT)
1645
1646         # As computer you can switch from a normal account to a workstation
1647         # or server trust account and back (also swapping between trust
1648         # accounts is allowed).
1649         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1650         # password yet.
1651         # With SYSTEM rights you can switch to a interdomain trust account.
1652
1653         # Invalid attribute
1654         try:
1655             m = Message()
1656             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1657             m["userAccountControl"] = MessageElement("0",
1658               FLAG_MOD_REPLACE, "userAccountControl")
1659             ldb.modify(m)
1660         except LdbError, (num, _):
1661             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1662
1663 # This has to wait until s4 supports it (needs a password module change)
1664 #        try:
1665 #            m = Message()
1666 #            m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1667 #            m["userAccountControl"] = MessageElement(
1668 #              str(UF_NORMAL_ACCOUNT),
1669 #              FLAG_MOD_REPLACE, "userAccountControl")
1670 #            ldb.modify(m)
1671 #        except LdbError, (num, _):
1672 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1673
1674         m = Message()
1675         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1676         m["userAccountControl"] = MessageElement(
1677           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1678           FLAG_MOD_REPLACE, "userAccountControl")
1679         ldb.modify(m)
1680
1681         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1682                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1683         self.assertTrue(len(res1) == 1)
1684         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1685           ATYPE_NORMAL_ACCOUNT)
1686
1687         try:
1688             m = Message()
1689             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1690             m["userAccountControl"] = MessageElement(
1691               str(UF_TEMP_DUPLICATE_ACCOUNT),
1692               FLAG_MOD_REPLACE, "userAccountControl")
1693             ldb.modify(m)
1694             self.fail()
1695         except LdbError, (num, _):
1696             self.assertEquals(num, ERR_OTHER)
1697
1698         m = Message()
1699         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1700         m["userAccountControl"] = MessageElement(
1701           str(UF_SERVER_TRUST_ACCOUNT),
1702           FLAG_MOD_REPLACE, "userAccountControl")
1703         ldb.modify(m)
1704
1705         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1706                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1707         self.assertTrue(len(res1) == 1)
1708         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1709           ATYPE_WORKSTATION_TRUST)
1710
1711         m = Message()
1712         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1713         m["userAccountControl"] = MessageElement(
1714           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1715           FLAG_MOD_REPLACE, "userAccountControl")
1716         ldb.modify(m)
1717
1718         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1719                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1720         self.assertTrue(len(res1) == 1)
1721         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1722           ATYPE_NORMAL_ACCOUNT)
1723
1724         m = Message()
1725         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1726         m["userAccountControl"] = MessageElement(
1727           str(UF_WORKSTATION_TRUST_ACCOUNT),
1728           FLAG_MOD_REPLACE, "userAccountControl")
1729         ldb.modify(m)
1730
1731         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1732                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1733         self.assertTrue(len(res1) == 1)
1734         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1735           ATYPE_WORKSTATION_TRUST)
1736
1737         m = Message()
1738         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1739         m["userAccountControl"] = MessageElement(
1740           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1741           FLAG_MOD_REPLACE, "userAccountControl")
1742         ldb.modify(m)
1743
1744         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1745                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1746         self.assertTrue(len(res1) == 1)
1747         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1748           ATYPE_NORMAL_ACCOUNT)
1749
1750         m = Message()
1751         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1752         m["userAccountControl"] = MessageElement(
1753           str(UF_SERVER_TRUST_ACCOUNT),
1754           FLAG_MOD_REPLACE, "userAccountControl")
1755         ldb.modify(m)
1756
1757         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1758                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1759         self.assertTrue(len(res1) == 1)
1760         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1761           ATYPE_WORKSTATION_TRUST)
1762
1763         m = Message()
1764         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1765         m["userAccountControl"] = MessageElement(
1766           str(UF_WORKSTATION_TRUST_ACCOUNT),
1767           FLAG_MOD_REPLACE, "userAccountControl")
1768         ldb.modify(m)
1769
1770         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1771                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1772         self.assertTrue(len(res1) == 1)
1773         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1774           ATYPE_WORKSTATION_TRUST)
1775
1776 # This isn't supported yet in s4 - needs ACL module adaption
1777 #        try:
1778 #            m = Message()
1779 #            m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1780 #            m["userAccountControl"] = MessageElement(
1781 #              str(UF_INTERDOMAIN_TRUST_ACCOUNT),
1782 #              FLAG_MOD_REPLACE, "userAccountControl")
1783 #            ldb.modify(m)
1784 #            self.fail()
1785 #        except LdbError, (num, _):
1786 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1787
1788         self.delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1789         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1790
1791     def test_dNSHostName(self):
1792         """Test the dNSHostName behaviour"""
1793         print "Testing dNSHostName behaviour\n"
1794
1795         ldb.add({
1796             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1797             "objectclass": "computer",
1798             "dNSHostName": "testname.testdom"})
1799
1800         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1801                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1802         self.assertTrue(len(res) == 1)
1803         self.assertFalse("servicePrincipalName" in res[0])
1804
1805         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1806
1807         ldb.add({
1808             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1809             "objectclass": "computer",
1810             "servicePrincipalName": "HOST/testname.testdom"})
1811
1812         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1813                           scope=SCOPE_BASE, attrs=["dNSHostName"])
1814         self.assertTrue(len(res) == 1)
1815         self.assertFalse("dNSHostName" in res[0])
1816
1817         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1818
1819         ldb.add({
1820             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1821             "objectclass": "computer",
1822             "dNSHostName": "testname2.testdom",
1823             "servicePrincipalName": "HOST/testname.testdom"})
1824
1825         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1826                           scope=SCOPE_BASE, attrs=["dNSHostName"])
1827         self.assertTrue(len(res) == 1)
1828         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
1829
1830         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1831                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1832         self.assertTrue(len(res) == 1)
1833         self.assertEquals(res[0]["servicePrincipalName"][0],
1834                           "HOST/testname.testdom")
1835
1836         m = Message()
1837         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1838         m["dNSHostName"] = MessageElement("testname.testdoM",
1839                                           FLAG_MOD_REPLACE, "dNSHostName")
1840         ldb.modify(m)
1841
1842         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1843                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1844         self.assertTrue(len(res) == 1)
1845         self.assertEquals(res[0]["servicePrincipalName"][0],
1846                           "HOST/testname.testdom")
1847
1848         m = Message()
1849         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1850         m["dNSHostName"] = MessageElement("testname2.testdom2",
1851                                           FLAG_MOD_REPLACE, "dNSHostName")
1852         ldb.modify(m)
1853
1854         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1855                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1856         self.assertTrue(len(res) == 1)
1857         self.assertEquals(res[0]["servicePrincipalName"][0],
1858                           "HOST/testname2.testdom2")
1859
1860         m = Message()
1861         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1862         m["dNSHostName"] = MessageElement([],
1863                                           FLAG_MOD_DELETE, "dNSHostName")
1864         ldb.modify(m)
1865
1866         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1867                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1868         self.assertTrue(len(res) == 1)
1869         self.assertEquals(res[0]["servicePrincipalName"][0],
1870                           "HOST/testname2.testdom2")
1871
1872         m = Message()
1873         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1874         m["dNSHostName"] = MessageElement("testname.testdom3",
1875                                           FLAG_MOD_REPLACE, "dNSHostName")
1876         ldb.modify(m)
1877
1878         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1879                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1880         self.assertTrue(len(res) == 1)
1881         self.assertEquals(res[0]["servicePrincipalName"][0],
1882                           "HOST/testname2.testdom2")
1883
1884         m = Message()
1885         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1886         m["dNSHostName"] = MessageElement("testname2.testdom2",
1887                                           FLAG_MOD_REPLACE, "dNSHostName")
1888         ldb.modify(m)
1889
1890         m = Message()
1891         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1892         m["dNSHostName"] = MessageElement("testname3.testdom3",
1893                                           FLAG_MOD_REPLACE, "dNSHostName")
1894         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom2",
1895                                                    FLAG_MOD_REPLACE,
1896                                                    "servicePrincipalName")
1897         ldb.modify(m)
1898
1899         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1900                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1901         self.assertTrue(len(res) == 1)
1902         self.assertEquals(res[0]["servicePrincipalName"][0],
1903                           "HOST/testname3.testdom3")
1904
1905         m = Message()
1906         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1907         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom2",
1908                                                    FLAG_MOD_REPLACE,
1909                                                    "servicePrincipalName")
1910         m["dNSHostName"] = MessageElement("testname4.testdom4",
1911                                           FLAG_MOD_REPLACE, "dNSHostName")
1912         ldb.modify(m)
1913
1914         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1915                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1916         self.assertTrue(len(res) == 1)
1917         self.assertEquals(res[0]["servicePrincipalName"][0],
1918                           "HOST/testname2.testdom2")
1919
1920         m = Message()
1921         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1922         m["servicePrincipalName"] = MessageElement([],
1923                                                    FLAG_MOD_DELETE,
1924                                                    "servicePrincipalName")
1925         ldb.modify(m)
1926
1927         m = Message()
1928         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1929         m["dNSHostName"] = MessageElement("testname2.testdom2",
1930                                           FLAG_MOD_REPLACE, "dNSHostName")
1931         ldb.modify(m)
1932
1933         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1934                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1935         self.assertTrue(len(res) == 1)
1936         self.assertFalse("servicePrincipalName" in res[0])
1937
1938         self.delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1939
1940
1941 if not "://" in host:
1942     if os.path.isfile(host):
1943         host = "tdb://%s" % host
1944     else:
1945         host = "ldap://%s" % host
1946
1947 ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp)
1948 if not "tdb://" in host:
1949     gc_ldb = Ldb("%s:3268" % host, credentials=creds,
1950                  session_info=system_session(), lp=lp)
1951 else:
1952     gc_ldb = None
1953
1954 runner = SubunitTestRunner()
1955 rc = 0
1956 if not runner.run(unittest.makeSuite(SamTests)).wasSuccessful():
1957     rc = 1
1958 sys.exit(rc)