4242fd6c63e2fb855109f389d32575f2e252e79d
[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 os
8
9 sys.path.append("bin/python")
10 import samba
11 samba.ensure_external_module("testtools", "testtools")
12 samba.ensure_external_module("subunit", "subunit/python")
13
14 import samba.getopt as options
15
16 from samba.auth import system_session
17 from ldb import SCOPE_BASE, LdbError
18 from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
19 from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
20 from ldb import ERR_OTHER, ERR_NO_SUCH_ATTRIBUTE
21 from ldb import ERR_OBJECT_CLASS_VIOLATION
22 from ldb import ERR_CONSTRAINT_VIOLATION
23 from ldb import ERR_UNDEFINED_ATTRIBUTE_TYPE
24 from ldb import Message, MessageElement, Dn
25 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
26 from samba.samdb import SamDB
27 from samba.dsdb import (UF_NORMAL_ACCOUNT,
28     UF_WORKSTATION_TRUST_ACCOUNT, UF_SERVER_TRUST_ACCOUNT,
29     UF_PARTIAL_SECRETS_ACCOUNT, UF_TEMP_DUPLICATE_ACCOUNT,
30     UF_PASSWD_NOTREQD, ATYPE_NORMAL_ACCOUNT,
31     GTYPE_SECURITY_BUILTIN_LOCAL_GROUP, GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
32     GTYPE_SECURITY_GLOBAL_GROUP, GTYPE_SECURITY_UNIVERSAL_GROUP,
33     GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP, GTYPE_DISTRIBUTION_GLOBAL_GROUP,
34     GTYPE_DISTRIBUTION_UNIVERSAL_GROUP,
35     ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_UNIVERSAL_GROUP,
36     ATYPE_SECURITY_LOCAL_GROUP, ATYPE_DISTRIBUTION_GLOBAL_GROUP,
37     ATYPE_DISTRIBUTION_UNIVERSAL_GROUP, ATYPE_DISTRIBUTION_LOCAL_GROUP,
38     ATYPE_WORKSTATION_TRUST)
39 from samba.dcerpc.security import (DOMAIN_RID_USERS, DOMAIN_RID_DOMAIN_MEMBERS,
40     DOMAIN_RID_DCS, DOMAIN_RID_READONLY_DCS)
41
42 from subunit.run import SubunitTestRunner
43 import unittest
44
45 from samba.ndr import ndr_unpack
46 from samba.dcerpc import security
47 from samba.tests import delete_force
48
49 parser = optparse.OptionParser("sam.py [options] <host>")
50 sambaopts = options.SambaOptions(parser)
51 parser.add_option_group(sambaopts)
52 parser.add_option_group(options.VersionOptions(parser))
53 # use command line creds if available
54 credopts = options.CredentialsOptions(parser)
55 parser.add_option_group(credopts)
56 opts, args = parser.parse_args()
57
58 if len(args) < 1:
59     parser.print_usage()
60     sys.exit(1)
61
62 host = args[0]
63
64 lp = sambaopts.get_loadparm()
65 creds = credopts.get_credentials(lp)
66
67 class SamTests(unittest.TestCase):
68
69     def setUp(self):
70         super(SamTests, self).setUp()
71         self.ldb = ldb
72         self.base_dn = ldb.domain_dn()
73
74         print "baseDN: %s\n" % self.base_dn
75
76         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
77         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
78         delete_force(self.ldb, "cn=ldaptest\,specialuser,cn=users," + self.base_dn)
79         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
80         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
81         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
82
83     def test_users_groups(self):
84         """This tests the SAM users and groups behaviour"""
85         print "Testing users and groups behaviour\n"
86
87         ldb.add({
88             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
89             "objectclass": "group"})
90
91         ldb.add({
92             "dn": "cn=ldaptestgroup2,cn=users," + self.base_dn,
93             "objectclass": "group"})
94
95         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
96                           scope=SCOPE_BASE, attrs=["objectSID"])
97         self.assertTrue(len(res1) == 1)
98         group_rid_1 = security.dom_sid(ldb.schema_format_value("objectSID",
99           res1[0]["objectSID"][0])).split()[1]
100
101         res1 = ldb.search("cn=ldaptestgroup2,cn=users," + self.base_dn,
102                           scope=SCOPE_BASE, attrs=["objectSID"])
103         self.assertTrue(len(res1) == 1)
104         group_rid_2 = security.dom_sid(ldb.schema_format_value("objectSID",
105           res1[0]["objectSID"][0])).split()[1]
106
107         # Try to create a user with an invalid account name
108         try:
109             ldb.add({
110                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
111                 "objectclass": "user",
112                 "sAMAccountName": "administrator"})
113             self.fail()
114         except LdbError, (num, _):
115             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
116         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
117
118         # Try to create a user with an invalid account name
119         try:
120             ldb.add({
121                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
122                 "objectclass": "user",
123                 "sAMAccountName": []})
124             self.fail()
125         except LdbError, (num, _):
126             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
127         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
128
129         # Try to create a user with an invalid primary group
130         try:
131             ldb.add({
132                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
133                 "objectclass": "user",
134                 "primaryGroupID": "0"})
135             self.fail()
136         except LdbError, (num, _):
137             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
138         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
139
140         # Try to Create a user with a valid primary group
141         try:
142             ldb.add({
143                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
144                 "objectclass": "user",
145                 "primaryGroupID": str(group_rid_1)})
146             self.fail()
147         except LdbError, (num, _):
148             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
149         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
150
151         # Test to see how we should behave when the user account doesn't
152         # exist
153         m = Message()
154         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
155         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
156           "primaryGroupID")
157         try:
158             ldb.modify(m)
159             self.fail()
160         except LdbError, (num, _):
161             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
162
163         # Test to see how we should behave when the account isn't a user
164         m = Message()
165         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
166         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
167           "primaryGroupID")
168         try:
169             ldb.modify(m)
170             self.fail()
171         except LdbError, (num, _):
172             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
173
174         # Test default primary groups on add operations
175
176         ldb.add({
177             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
178             "objectclass": "user"})
179
180         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
181                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
182         self.assertTrue(len(res1) == 1)
183         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
184
185         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
186
187         ldb.add({
188             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
189             "objectclass": "user",
190             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD) })
191
192         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
193                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
194         self.assertTrue(len(res1) == 1)
195         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
196
197         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
198
199         # unfortunately the INTERDOMAIN_TRUST_ACCOUNT case cannot be tested
200         # since such accounts aren't directly creatable (ACCESS_DENIED)
201
202         ldb.add({
203             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
204             "objectclass": "computer",
205             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
206
207         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
208                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
209         self.assertTrue(len(res1) == 1)
210         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DOMAIN_MEMBERS))
211
212         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
213
214         ldb.add({
215             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
216             "objectclass": "computer",
217             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
218
219         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
220                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
221         self.assertTrue(len(res1) == 1)
222         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DCS))
223
224         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
225
226         # Read-only DC accounts are only creatable by
227         # UF_WORKSTATION_TRUST_ACCOUNT and work only on DCs >= 2008 (therefore
228         # we have a fallback in the assertion)
229         ldb.add({
230             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
231             "objectclass": "computer",
232             "userAccountControl": str(UF_PARTIAL_SECRETS_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD) })
233
234         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
235                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
236         self.assertTrue(len(res1) == 1)
237         self.assertTrue(res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_READONLY_DCS) or
238                         res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_DOMAIN_MEMBERS))
239
240         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
241
242         # Test default primary groups on modify operations
243
244         ldb.add({
245             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
246             "objectclass": "user"})
247
248         m = Message()
249         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
250         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
251           "userAccountControl")
252         ldb.modify(m)
253
254         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
255                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
256         self.assertTrue(len(res1) == 1)
257         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
258
259         # unfortunately the INTERDOMAIN_TRUST_ACCOUNT case cannot be tested
260         # since such accounts aren't directly creatable (ACCESS_DENIED)
261
262         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
263
264         ldb.add({
265             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
266             "objectclass": "computer"})
267
268         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
269                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
270         self.assertTrue(len(res1) == 1)
271         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_USERS))
272
273         m = Message()
274         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
275         m["userAccountControl"] = MessageElement(str(UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
276           "userAccountControl")
277         ldb.modify(m)
278
279         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
280                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
281         self.assertTrue(len(res1) == 1)
282         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DOMAIN_MEMBERS))
283
284         m = Message()
285         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
286         m["userAccountControl"] = MessageElement(str(UF_SERVER_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
287           "userAccountControl")
288         ldb.modify(m)
289
290         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
291                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
292         self.assertTrue(len(res1) == 1)
293         self.assertEquals(res1[0]["primaryGroupID"][0], str(DOMAIN_RID_DCS))
294
295         # Read-only DC accounts are only creatable by
296         # UF_WORKSTATION_TRUST_ACCOUNT and work only on DCs >= 2008 (therefore
297         # we have a fallback in the assertion)
298         m = Message()
299         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
300         m["userAccountControl"] = MessageElement(str(UF_PARTIAL_SECRETS_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_REPLACE,
301           "userAccountControl")
302         ldb.modify(m)
303
304         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
305                           scope=SCOPE_BASE, attrs=["primaryGroupID"])
306         self.assertTrue(len(res1) == 1)
307         self.assertTrue(res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_READONLY_DCS) or
308                         res1[0]["primaryGroupID"][0] == str(DOMAIN_RID_DOMAIN_MEMBERS))
309
310         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
311
312         # Recreate account for further tests
313
314         ldb.add({
315             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
316             "objectclass": "user"})
317
318         # Try to set an invalid account name
319         m = Message()
320         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
321         m["sAMAccountName"] = MessageElement("administrator", FLAG_MOD_REPLACE,
322           "sAMAccountName")
323         try:
324             ldb.modify(m)
325             self.fail()
326         except LdbError, (num, _):
327             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
328
329         # But to reset the actual "sAMAccountName" should still be possible
330         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
331                           scope=SCOPE_BASE, attrs=["sAMAccountName"])
332         self.assertTrue(len(res1) == 1)
333         m = Message()
334         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
335         m["sAMAccountName"] = MessageElement(res1[0]["sAMAccountName"][0], FLAG_MOD_REPLACE,
336           "sAMAccountName")
337         ldb.modify(m)
338
339         # And another (free) name should be possible as well
340         m = Message()
341         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
342         m["sAMAccountName"] = MessageElement("xxx_ldaptestuser_xxx", FLAG_MOD_REPLACE,
343           "sAMAccountName")
344         ldb.modify(m)
345
346         # We should be able to reset our actual primary group
347         m = Message()
348         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
349         m["primaryGroupID"] = MessageElement(str(DOMAIN_RID_USERS), FLAG_MOD_REPLACE,
350           "primaryGroupID")
351         ldb.modify(m)
352
353         # Try to add invalid primary group
354         m = Message()
355         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
356         m["primaryGroupID"] = MessageElement("0", FLAG_MOD_REPLACE,
357           "primaryGroupID")
358         try:
359             ldb.modify(m)
360             self.fail()
361         except LdbError, (num, _):
362             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
363
364         # Try to make group 1 primary - should be denied since it is not yet
365         # secondary
366         m = Message()
367         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
368         m["primaryGroupID"] = MessageElement(str(group_rid_1),
369           FLAG_MOD_REPLACE, "primaryGroupID")
370         try:
371             ldb.modify(m)
372             self.fail()
373         except LdbError, (num, _):
374             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
375
376         # Make group 1 secondary
377         m = Message()
378         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
379         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
380                                      FLAG_MOD_REPLACE, "member")
381         ldb.modify(m)
382
383         # Make group 1 primary
384         m = Message()
385         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
386         m["primaryGroupID"] = MessageElement(str(group_rid_1),
387           FLAG_MOD_REPLACE, "primaryGroupID")
388         ldb.modify(m)
389
390         # Try to delete group 1 - should be denied
391         try:
392             ldb.delete("cn=ldaptestgroup,cn=users," + self.base_dn)
393             self.fail()
394         except LdbError, (num, _):
395             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
396
397         # Try to add group 1 also as secondary - should be denied
398         m = Message()
399         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
400         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
401                                      FLAG_MOD_ADD, "member")
402         try:
403             ldb.modify(m)
404             self.fail()
405         except LdbError, (num, _):
406             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
407
408         # Try to add invalid member to group 1 - should be denied
409         m = Message()
410         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
411         m["member"] = MessageElement(
412           "cn=ldaptestuser3,cn=users," + self.base_dn,
413           FLAG_MOD_ADD, "member")
414         try:
415             ldb.modify(m)
416             self.fail()
417         except LdbError, (num, _):
418             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
419
420         # Make group 2 secondary
421         m = Message()
422         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
423         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
424                                      FLAG_MOD_ADD, "member")
425         ldb.modify(m)
426
427         # Swap the groups
428         m = Message()
429         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
430         m["primaryGroupID"] = MessageElement(str(group_rid_2),
431           FLAG_MOD_REPLACE, "primaryGroupID")
432         ldb.modify(m)
433
434         # Swap the groups (does not really make sense but does the same)
435         m = Message()
436         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
437         m["primaryGroupID"] = MessageElement(str(group_rid_1),
438           FLAG_MOD_REPLACE, "primaryGroupID")
439         m["primaryGroupID"] = MessageElement(str(group_rid_2),
440           FLAG_MOD_REPLACE, "primaryGroupID")
441         ldb.modify(m)
442
443         # Old primary group should contain a "member" attribute for the user,
444         # the new shouldn't contain anymore one
445         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
446                           scope=SCOPE_BASE, attrs=["member"])
447         self.assertTrue(len(res1) == 1)
448         self.assertTrue(len(res1[0]["member"]) == 1)
449         self.assertEquals(res1[0]["member"][0].lower(),
450           ("cn=ldaptestuser,cn=users," + self.base_dn).lower())
451
452         res1 = ldb.search("cn=ldaptestgroup2, cn=users," + self.base_dn,
453                           scope=SCOPE_BASE, attrs=["member"])
454         self.assertTrue(len(res1) == 1)
455         self.assertFalse("member" in res1[0])
456
457         # Primary group member
458         m = Message()
459         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
460         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
461                                      FLAG_MOD_DELETE, "member")
462         try:
463             ldb.modify(m)
464             self.fail()
465         except LdbError, (num, _):
466             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
467
468         # Delete invalid group member
469         m = Message()
470         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
471         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
472                                      FLAG_MOD_DELETE, "member")
473         try:
474             ldb.modify(m)
475             self.fail()
476         except LdbError, (num, _):
477             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
478
479         # Also this should be denied
480         try:
481             ldb.add({
482               "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
483               "objectclass": "user",
484               "primaryGroupID": "0"})
485             self.fail()
486         except LdbError, (num, _):
487             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
488
489         # Recreate user accounts
490
491         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
492
493         ldb.add({
494             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
495             "objectclass": "user"})
496
497         ldb.add({
498             "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
499             "objectclass": "user"})
500
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                                      FLAG_MOD_ADD, "member")
505         ldb.modify(m)
506
507         # Already added
508         m = Message()
509         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
510         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
511                                      FLAG_MOD_ADD, "member")
512         try:
513             ldb.modify(m)
514             self.fail()
515         except LdbError, (num, _):
516             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
517
518         # Already added, but as <SID=...>
519         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
520                           scope=SCOPE_BASE, attrs=["objectSid"])
521         self.assertTrue(len(res1) == 1)
522         sid_bin = res1[0]["objectSid"][0]
523         sid_str = ("<SID=" + ldb.schema_format_value("objectSid", sid_bin) + ">").upper()
524
525         m = Message()
526         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
527         m["member"] = MessageElement(sid_str, FLAG_MOD_ADD, "member")
528         try:
529             ldb.modify(m)
530             self.fail()
531         except LdbError, (num, _):
532             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
533
534         # Invalid member
535         m = Message()
536         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
537         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
538                                      FLAG_MOD_REPLACE, "member")
539         try:
540             ldb.modify(m)
541             self.fail()
542         except LdbError, (num, _):
543             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
544
545         # Invalid member
546         m = Message()
547         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
548         m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn,
549                                       "cn=ldaptestuser1,cn=users," + self.base_dn],
550                                      FLAG_MOD_REPLACE, "member")
551         try:
552             ldb.modify(m)
553             self.fail()
554         except LdbError, (num, _):
555             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
556
557         # Invalid member
558         m = Message()
559         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
560         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
561                                      FLAG_MOD_REPLACE, "member")
562         m["member"] = MessageElement("cn=ldaptestuser1,cn=users," + self.base_dn,
563                                      FLAG_MOD_ADD, "member")
564         try:
565             ldb.modify(m)
566             self.fail()
567         except LdbError, (num, _):
568             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
569
570         m = Message()
571         m.dn = Dn(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
572         m["member"] = MessageElement(["cn=ldaptestuser,cn=users," + self.base_dn,
573                                       "cn=ldaptestuser2,cn=users," + self.base_dn],
574                                      FLAG_MOD_REPLACE, "member")
575         ldb.modify(m)
576
577         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
578         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
579         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
580         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
581
582         # Make also a small test for accounts with special DNs ("," in this case)
583         ldb.add({
584             "dn": "cn=ldaptest\,specialuser,cn=users," + self.base_dn,
585             "objectclass": "user"})
586         delete_force(self.ldb, "cn=ldaptest\,specialuser,cn=users," + self.base_dn)
587
588     def test_sam_attributes(self):
589         """Test the behaviour of special attributes of SAM objects"""
590         print "Testing the behaviour of special attributes of SAM objects\n"""
591
592         ldb.add({
593             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
594             "objectclass": "user"})
595         ldb.add({
596             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
597             "objectclass": "group"})
598
599         m = Message()
600         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
601         m["groupType"] = MessageElement(str(GTYPE_SECURITY_GLOBAL_GROUP), FLAG_MOD_ADD,
602           "groupType")
603         try:
604             ldb.modify(m)
605             self.fail()
606         except LdbError, (num, _):
607             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
608
609         # Delete protection tests
610
611         for attr in ["nTSecurityDescriptor", "objectSid", "sAMAccountType",
612                      "sAMAccountName", "groupType"]:
613
614             m = Message()
615             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
616             m[attr] = MessageElement([], FLAG_MOD_REPLACE, attr)
617             try:
618                 ldb.modify(m)
619                 self.fail()
620             except LdbError, (num, _):
621                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
622
623             m = Message()
624             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
625             m[attr] = MessageElement([], FLAG_MOD_DELETE, attr)
626             try:
627                 ldb.modify(m)
628                 self.fail()
629             except LdbError, (num, _):
630                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
631
632         m = Message()
633         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
634         m["primaryGroupID"] = MessageElement("513", FLAG_MOD_ADD,
635           "primaryGroupID")
636         try:
637             ldb.modify(m)
638             self.fail()
639         except LdbError, (num, _):
640             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
641
642         m = Message()
643         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
644         m["userAccountControl"] = MessageElement(str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD), FLAG_MOD_ADD,
645           "userAccountControl")
646         try:
647             ldb.modify(m)
648             self.fail()
649         except LdbError, (num, _):
650             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
651
652         m = Message()
653         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
654         m["objectSid"] = MessageElement("xxxxxxxxxxxxxxxx", FLAG_MOD_ADD,
655           "objectSid")
656         try:
657             ldb.modify(m)
658             self.fail()
659         except LdbError, (num, _):
660             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
661
662         m = Message()
663         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
664         m["sAMAccountType"] = MessageElement("0", FLAG_MOD_ADD,
665           "sAMAccountType")
666         try:
667             ldb.modify(m)
668             self.fail()
669         except LdbError, (num, _):
670             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
671
672         m = Message()
673         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
674         m["sAMAccountName"] = MessageElement("test", FLAG_MOD_ADD,
675           "sAMAccountName")
676         try:
677             ldb.modify(m)
678             self.fail()
679         except LdbError, (num, _):
680             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
681
682         # Delete protection tests
683
684         for attr in ["nTSecurityDescriptor", "objectSid", "sAMAccountType",
685                      "sAMAccountName", "primaryGroupID", "userAccountControl",
686                      "accountExpires", "badPasswordTime", "badPwdCount",
687                      "codePage", "countryCode", "lastLogoff", "lastLogon",
688                      "logonCount", "pwdLastSet"]:
689
690             m = Message()
691             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
692             m[attr] = MessageElement([], FLAG_MOD_REPLACE, attr)
693             try:
694                 ldb.modify(m)
695                 self.fail()
696             except LdbError, (num, _):
697                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
698
699             m = Message()
700             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
701             m[attr] = MessageElement([], FLAG_MOD_DELETE, attr)
702             try:
703                 ldb.modify(m)
704                 self.fail()
705             except LdbError, (num, _):
706                 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
707
708         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
709         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
710
711     def test_primary_group_token_constructed(self):
712         """Test the primary group token behaviour (hidden-generated-readonly attribute on groups) and some other constructed attributes"""
713         print "Testing primary group token behaviour and other constructed attributes\n"
714
715         try:
716             ldb.add({
717                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
718                 "objectclass": "group",
719                 "primaryGroupToken": "100"})
720             self.fail()
721         except LdbError, (num, _):
722             self.assertEquals(num, ERR_UNDEFINED_ATTRIBUTE_TYPE)
723         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
724
725         ldb.add({
726             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
727             "objectclass": "user"})
728
729         ldb.add({
730             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
731             "objectclass": "group"})
732
733         # Testing for one invalid, and one valid operational attribute, but also the things they are built from
734         res1 = ldb.search(self.base_dn,
735                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName", "objectClass", "objectSid"])
736         self.assertTrue(len(res1) == 1)
737         self.assertFalse("primaryGroupToken" in res1[0])
738         self.assertTrue("canonicalName" in res1[0])
739         self.assertTrue("objectClass" in res1[0])
740         self.assertTrue("objectSid" in res1[0])
741
742         res1 = ldb.search(self.base_dn,
743                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "canonicalName"])
744         self.assertTrue(len(res1) == 1)
745         self.assertFalse("primaryGroupToken" in res1[0])
746         self.assertFalse("objectSid" in res1[0])
747         self.assertFalse("objectClass" in res1[0])
748         self.assertTrue("canonicalName" in res1[0])
749
750         res1 = ldb.search("cn=users," + self.base_dn,
751                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
752         self.assertTrue(len(res1) == 1)
753         self.assertFalse("primaryGroupToken" in res1[0])
754
755         res1 = ldb.search("cn=ldaptestuser, cn=users," + self.base_dn,
756                           scope=SCOPE_BASE, attrs=["primaryGroupToken"])
757         self.assertTrue(len(res1) == 1)
758         self.assertFalse("primaryGroupToken" in res1[0])
759
760         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
761                           scope=SCOPE_BASE)
762         self.assertTrue(len(res1) == 1)
763         self.assertFalse("primaryGroupToken" in res1[0])
764
765         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
766                           scope=SCOPE_BASE, attrs=["primaryGroupToken", "objectSID"])
767         self.assertTrue(len(res1) == 1)
768         primary_group_token = int(res1[0]["primaryGroupToken"][0])
769
770         rid = security.dom_sid(ldb.schema_format_value("objectSID", res1[0]["objectSID"][0])).split()[1]
771         self.assertEquals(primary_group_token, rid)
772
773         m = Message()
774         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
775         m["primaryGroupToken"] = "100"
776         try:
777             ldb.modify(m)
778             self.fail()
779         except LdbError, (num, _):
780             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
781
782         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
783         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
784
785     def test_tokenGroups(self):
786         """Test the tokenGroups behaviour (hidden-generated-readonly attribute on SAM objects)"""
787         print "Testing tokenGroups behaviour\n"
788
789         # The domain object shouldn't contain any "tokenGroups" entry
790         res = ldb.search(self.base_dn, scope=SCOPE_BASE, attrs=["tokenGroups"])
791         self.assertTrue(len(res) == 1)
792         self.assertFalse("tokenGroups" in res[0])
793
794         # The domain administrator should contain "tokenGroups" entries
795         # (the exact number depends on the domain/forest function level and the
796         # DC software versions)
797         res = ldb.search("cn=Administrator,cn=Users," + self.base_dn,
798                          scope=SCOPE_BASE, attrs=["tokenGroups"])
799         self.assertTrue(len(res) == 1)
800         self.assertTrue("tokenGroups" in res[0])
801
802         ldb.add({
803             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
804             "objectclass": "user"})
805
806         # This testuser should contain at least two "tokenGroups" entries
807         # (exactly two on an unmodified "Domain Users" and "Users" group)
808         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
809                          scope=SCOPE_BASE, attrs=["tokenGroups"])
810         self.assertTrue(len(res) == 1)
811         self.assertTrue(len(res[0]["tokenGroups"]) >= 2)
812
813         # one entry which we need to find should point to domains "Domain Users"
814         # group and another entry should point to the builtin "Users"group
815         domain_users_group_found = False
816         users_group_found = False
817         for sid in res[0]["tokenGroups"]:
818             rid = security.dom_sid(ldb.schema_format_value("objectSID", sid)).split()[1]
819             if rid == 513:
820                 domain_users_group_found = True
821             if rid == 545:
822                 users_group_found = True
823
824         self.assertTrue(domain_users_group_found)
825         self.assertTrue(users_group_found)
826
827         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
828
829     def test_groupType(self):
830         """Test the groupType behaviour"""
831         print "Testing groupType behaviour\n"
832
833         # You can never create or change to a
834         # "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP"
835
836         # Add operation
837
838         # Invalid attribute
839         try:
840             ldb.add({
841                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
842                 "objectclass": "group",
843                 "groupType": "0"})
844             self.fail()
845         except LdbError, (num, _):
846             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
847         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
848
849         try:
850             ldb.add({
851                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
852                 "objectclass": "group",
853                 "groupType": str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP)})
854             self.fail()
855         except LdbError, (num, _):
856             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
857         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
858
859         ldb.add({
860             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
861             "objectclass": "group",
862             "groupType": str(GTYPE_SECURITY_GLOBAL_GROUP)})
863
864         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
865                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
866         self.assertTrue(len(res1) == 1)
867         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
868           ATYPE_SECURITY_GLOBAL_GROUP)
869         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
870
871         ldb.add({
872             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
873             "objectclass": "group",
874             "groupType": str(GTYPE_SECURITY_UNIVERSAL_GROUP)})
875
876         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
877                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
878         self.assertTrue(len(res1) == 1)
879         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
880           ATYPE_SECURITY_UNIVERSAL_GROUP)
881         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
882
883         ldb.add({
884             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
885             "objectclass": "group",
886             "groupType": str(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP)})
887
888         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
889                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
890         self.assertTrue(len(res1) == 1)
891         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
892           ATYPE_SECURITY_LOCAL_GROUP)
893         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
894
895         ldb.add({
896             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
897             "objectclass": "group",
898             "groupType": str(GTYPE_DISTRIBUTION_GLOBAL_GROUP)})
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_DISTRIBUTION_GLOBAL_GROUP)
905         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
906
907         ldb.add({
908             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
909             "objectclass": "group",
910             "groupType": str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP)})
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_DISTRIBUTION_UNIVERSAL_GROUP)
917         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
918
919         ldb.add({
920             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
921             "objectclass": "group",
922             "groupType": str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)})
923
924         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
925                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
926         self.assertTrue(len(res1) == 1)
927         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
928           ATYPE_DISTRIBUTION_LOCAL_GROUP)
929         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
930
931         # Modify operation
932
933         ldb.add({
934             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
935             "objectclass": "group"})
936
937         # We can change in this direction: global <-> universal <-> local
938         # On each step also the group type itself (security/distribution) is
939         # variable.
940
941         # After creation we should have a "security global group"
942         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
943                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
944         self.assertTrue(len(res1) == 1)
945         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
946           ATYPE_SECURITY_GLOBAL_GROUP)
947
948         # Invalid attribute
949         try:
950             m = Message()
951             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
952             m["groupType"] = MessageElement("0",
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         # Security 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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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_SECURITY_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 to "builtin local" (shouldn't work)
1063
1064         try:
1065             m = Message()
1066             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1067             m["groupType"] = MessageElement(
1068               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1069               FLAG_MOD_REPLACE, "groupType")
1070             ldb.modify(m)
1071             self.fail()
1072         except LdbError, (num, _):
1073             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1074
1075         m = Message()
1076         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1077
1078         # Change back to "universal"
1079
1080         m = Message()
1081         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1082         m["groupType"] = MessageElement(
1083          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1084           FLAG_MOD_REPLACE, "groupType")
1085         ldb.modify(m)
1086
1087         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1088                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1089         self.assertTrue(len(res1) == 1)
1090         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1091           ATYPE_SECURITY_UNIVERSAL_GROUP)
1092
1093         # Change to "builtin local" (shouldn't work)
1094
1095         try:
1096             m = Message()
1097             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1098             m["groupType"] = MessageElement(
1099               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1100               FLAG_MOD_REPLACE, "groupType")
1101             ldb.modify(m)
1102             self.fail()
1103         except LdbError, (num, _):
1104             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1105
1106         # Change back to "global"
1107
1108         m = Message()
1109         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1110         m["groupType"] = MessageElement(
1111           str(GTYPE_SECURITY_GLOBAL_GROUP),
1112           FLAG_MOD_REPLACE, "groupType")
1113         ldb.modify(m)
1114
1115         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1116                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1117         self.assertTrue(len(res1) == 1)
1118         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1119           ATYPE_SECURITY_GLOBAL_GROUP)
1120
1121         # Change to "builtin local" (shouldn't work)
1122
1123         try:
1124             m = Message()
1125             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1126             m["groupType"] = MessageElement(
1127               str(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP),
1128               FLAG_MOD_REPLACE, "groupType")
1129             ldb.modify(m)
1130             self.fail()
1131         except LdbError, (num, _):
1132             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1133
1134         # Distribution groups
1135
1136         # Default is "global group"
1137
1138         m = Message()
1139         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1140         m["groupType"] = MessageElement(
1141           str(GTYPE_DISTRIBUTION_GLOBAL_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_GLOBAL_GROUP)
1150
1151         # Change to local (shouldn't work)
1152
1153         try:
1154             m = Message()
1155             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1156             m["groupType"] = MessageElement(
1157               str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1158               FLAG_MOD_REPLACE, "groupType")
1159             ldb.modify(m)
1160             self.fail()
1161         except LdbError, (num, _):
1162             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1163
1164         # Change to "universal"
1165
1166         m = Message()
1167         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1168         m["groupType"] = MessageElement(
1169          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1170           FLAG_MOD_REPLACE, "groupType")
1171         ldb.modify(m)
1172
1173         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1174                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1175         self.assertTrue(len(res1) == 1)
1176         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1177           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1178
1179         # Change back to "global"
1180
1181         m = Message()
1182         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1183         m["groupType"] = MessageElement(
1184           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1185           FLAG_MOD_REPLACE, "groupType")
1186         ldb.modify(m)
1187
1188         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1189                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1190         self.assertTrue(len(res1) == 1)
1191         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1192           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1193
1194         # Change back to "universal"
1195
1196         m = Message()
1197         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1198         m["groupType"] = MessageElement(
1199          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1200           FLAG_MOD_REPLACE, "groupType")
1201         ldb.modify(m)
1202
1203         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1204                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1205         self.assertTrue(len(res1) == 1)
1206         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1207           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1208
1209         # Change to "local"
1210
1211         m = Message()
1212         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1213         m["groupType"] = MessageElement(
1214           str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_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_DISTRIBUTION_LOCAL_GROUP)
1223
1224         # Change to "global" (shouldn't work)
1225
1226         try:
1227             m = Message()
1228             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1229             m["groupType"] = MessageElement(
1230               str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1231               FLAG_MOD_REPLACE, "groupType")
1232             ldb.modify(m)
1233             self.fail()
1234         except LdbError, (num, _):
1235             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1236
1237         # Change back to "universal"
1238
1239         # Try to add invalid member to group 1 - should be denied
1240         m = Message()
1241         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1242         m["member"] = MessageElement(
1243           "cn=ldaptestuser3,cn=users," + self.base_dn,
1244           FLAG_MOD_ADD, "member")
1245         try:
1246             ldb.modify(m)
1247             self.fail()
1248         except LdbError, (num, _):
1249             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1250
1251         # Make group 2 secondary
1252         m = Message()
1253         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1254         m["groupType"] = MessageElement(
1255          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1256           FLAG_MOD_REPLACE, "groupType")
1257         ldb.modify(m)
1258
1259         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1260                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1261         self.assertTrue(len(res1) == 1)
1262         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1263           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1264
1265         # Change back to "global"
1266
1267         m = Message()
1268         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1269         m["groupType"] = MessageElement(
1270           str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1271           FLAG_MOD_REPLACE, "groupType")
1272         ldb.modify(m)
1273
1274         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1275                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1276         self.assertTrue(len(res1) == 1)
1277         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1278           ATYPE_DISTRIBUTION_GLOBAL_GROUP)
1279
1280         # Both group types: this performs only random checks - all possibilities
1281         # would require too much code.
1282
1283         # Default is "global group"
1284
1285         m = Message()
1286         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1287         m["groupType"] = MessageElement(
1288           str(GTYPE_SECURITY_GLOBAL_GROUP),
1289           FLAG_MOD_REPLACE, "groupType")
1290         ldb.modify(m)
1291
1292         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1293                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1294         self.assertTrue(len(res1) == 1)
1295         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1296           ATYPE_SECURITY_GLOBAL_GROUP)
1297
1298         # Change to "local" (shouldn't work)
1299
1300         try:
1301             m = Message()
1302             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1303             m["groupType"] = MessageElement(
1304               str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1305               FLAG_MOD_REPLACE, "groupType")
1306             ldb.modify(m)
1307             self.fail()
1308         except LdbError, (num, _):
1309             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1310
1311         # Change to "universal"
1312
1313         m = Message()
1314         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1315         m["groupType"] = MessageElement(
1316          str(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP),
1317           FLAG_MOD_REPLACE, "groupType")
1318         ldb.modify(m)
1319
1320         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1321                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1322         self.assertTrue(len(res1) == 1)
1323         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1324           ATYPE_DISTRIBUTION_UNIVERSAL_GROUP)
1325
1326         # Change back to "global"
1327
1328         m = Message()
1329         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1330         m["groupType"] = MessageElement(
1331           str(GTYPE_SECURITY_GLOBAL_GROUP),
1332           FLAG_MOD_REPLACE, "groupType")
1333         ldb.modify(m)
1334
1335         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1336                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1337         self.assertTrue(len(res1) == 1)
1338         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1339           ATYPE_SECURITY_GLOBAL_GROUP)
1340
1341         # Change back to "universal"
1342
1343         m = Message()
1344         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1345         m["groupType"] = MessageElement(
1346          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1347           FLAG_MOD_REPLACE, "groupType")
1348         ldb.modify(m)
1349
1350         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1351                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1352         self.assertTrue(len(res1) == 1)
1353         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1354           ATYPE_SECURITY_UNIVERSAL_GROUP)
1355
1356         # Change to "local"
1357
1358         m = Message()
1359         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1360         m["groupType"] = MessageElement(
1361           str(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP),
1362           FLAG_MOD_REPLACE, "groupType")
1363         ldb.modify(m)
1364
1365         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1366                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1367         self.assertTrue(len(res1) == 1)
1368         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1369           ATYPE_DISTRIBUTION_LOCAL_GROUP)
1370
1371         # Change to "global" (shouldn't work)
1372
1373         try:
1374             m = Message()
1375             m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1376             m["groupType"] = MessageElement(
1377               str(GTYPE_DISTRIBUTION_GLOBAL_GROUP),
1378               FLAG_MOD_REPLACE, "groupType")
1379             ldb.modify(m)
1380             self.fail()
1381         except LdbError, (num, _):
1382             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1383
1384         # Change back to "universal"
1385
1386         m = Message()
1387         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1388         m["groupType"] = MessageElement(
1389          str(GTYPE_SECURITY_UNIVERSAL_GROUP),
1390           FLAG_MOD_REPLACE, "groupType")
1391         ldb.modify(m)
1392
1393         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1394                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1395         self.assertTrue(len(res1) == 1)
1396         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1397           ATYPE_SECURITY_UNIVERSAL_GROUP)
1398
1399         # Change back to "global"
1400
1401         m = Message()
1402         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1403         m["groupType"] = MessageElement(
1404           str(GTYPE_SECURITY_GLOBAL_GROUP),
1405           FLAG_MOD_REPLACE, "groupType")
1406         ldb.modify(m)
1407
1408         res1 = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1409                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1410         self.assertTrue(len(res1) == 1)
1411         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1412           ATYPE_SECURITY_GLOBAL_GROUP)
1413
1414         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1415
1416     def test_userAccountControl(self):
1417         """Test the userAccountControl behaviour"""
1418         print "Testing userAccountControl behaviour\n"
1419
1420         # With a user object
1421
1422         # Add operation
1423
1424         # As user you can only set a normal account.
1425         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1426         # password yet.
1427         # With SYSTEM rights you can set a interdomain trust account.
1428
1429         # Invalid attribute
1430         try:
1431             ldb.add({
1432                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1433                 "objectclass": "user",
1434                 "userAccountControl": "0"})
1435             self.fail()
1436         except LdbError, (num, _):
1437             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1438         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1439
1440 # This has to wait until s4 supports it (needs a password module change)
1441 #        try:
1442 #            ldb.add({
1443 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1444 #                "objectclass": "user",
1445 #                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1446 #            self.fail()
1447 #        except LdbError, (num, _):
1448 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1449 #        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1450
1451         ldb.add({
1452             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1453             "objectclass": "user",
1454             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1455
1456         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1457                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1458         self.assertTrue(len(res1) == 1)
1459         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1460           ATYPE_NORMAL_ACCOUNT)
1461         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1462
1463         try:
1464             ldb.add({
1465                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1466                 "objectclass": "user",
1467                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1468             self.fail()
1469         except LdbError, (num, _):
1470             self.assertEquals(num, ERR_OTHER)
1471         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1472
1473 # This isn't supported yet in s4
1474 #        try:
1475 #            ldb.add({
1476 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1477 #                "objectclass": "user",
1478 #                "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1479 #            self.fail()
1480 #        except LdbError, (num, _):
1481 #            self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1482 #        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1483 #
1484 #        try:
1485 #            ldb.add({
1486 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1487 #                "objectclass": "user",
1488 #                "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1489 #        except LdbError, (num, _):
1490 #            self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1491 #        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1492
1493 # This isn't supported yet in s4 - needs ACL module adaption
1494 #        try:
1495 #            ldb.add({
1496 #                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1497 #                "objectclass": "user",
1498 #                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1499 #            self.fail()
1500 #        except LdbError, (num, _):
1501 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1502 #        delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1503
1504         # Modify operation
1505
1506         ldb.add({
1507             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1508             "objectclass": "user"})
1509
1510         # After creation we should have a normal account
1511         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1512                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1513         self.assertTrue(len(res1) == 1)
1514         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1515           ATYPE_NORMAL_ACCOUNT)
1516
1517         # As user you can only switch from a normal account to a workstation
1518         # trust account and back.
1519         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1520         # password yet.
1521         # With SYSTEM rights you can switch to a interdomain trust account.
1522
1523         # Invalid attribute
1524         try:
1525             m = Message()
1526             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1527             m["userAccountControl"] = MessageElement("0",
1528               FLAG_MOD_REPLACE, "userAccountControl")
1529             ldb.modify(m)
1530         except LdbError, (num, _):
1531             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1532
1533 # This has to wait until s4 supports it (needs a password module change)
1534 #        try:
1535 #            m = Message()
1536 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1537 #            m["userAccountControl"] = MessageElement(
1538 #              str(UF_NORMAL_ACCOUNT),
1539 #              FLAG_MOD_REPLACE, "userAccountControl")
1540 #            ldb.modify(m)
1541 #        except LdbError, (num, _):
1542 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1543
1544         m = Message()
1545         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1546         m["userAccountControl"] = MessageElement(
1547           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1548           FLAG_MOD_REPLACE, "userAccountControl")
1549         ldb.modify(m)
1550
1551         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1552                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1553         self.assertTrue(len(res1) == 1)
1554         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1555           ATYPE_NORMAL_ACCOUNT)
1556
1557         try:
1558             m = Message()
1559             m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1560             m["userAccountControl"] = MessageElement(
1561               str(UF_TEMP_DUPLICATE_ACCOUNT),
1562               FLAG_MOD_REPLACE, "userAccountControl")
1563             ldb.modify(m)
1564             self.fail()
1565         except LdbError, (num, _):
1566             self.assertEquals(num, ERR_OTHER)
1567
1568 # This isn't supported yet in s4
1569 #        try:
1570 #            m = Message()
1571 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1572 #            m["userAccountControl"] = MessageElement(
1573 #              str(UF_SERVER_TRUST_ACCOUNT),
1574 #              FLAG_MOD_REPLACE, "userAccountControl")
1575 #            ldb.modify(m)
1576 #            self.fail()
1577 #        except LdbError, (num, _):
1578 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1579
1580         m = Message()
1581         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1582         m["userAccountControl"] = MessageElement(
1583           str(UF_WORKSTATION_TRUST_ACCOUNT),
1584           FLAG_MOD_REPLACE, "userAccountControl")
1585         ldb.modify(m)
1586
1587         res1 = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
1588                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1589         self.assertTrue(len(res1) == 1)
1590         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1591           ATYPE_WORKSTATION_TRUST)
1592
1593         m = Message()
1594         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1595         m["userAccountControl"] = MessageElement(
1596           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1597           FLAG_MOD_REPLACE, "userAccountControl")
1598         ldb.modify(m)
1599
1600         res1 = ldb.search("cn=ldaptestuser,cn=users," + 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_NORMAL_ACCOUNT)
1605
1606 # This isn't supported yet in s4 - needs ACL module adaption
1607 #        try:
1608 #            m = Message()
1609 #            m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1610 #            m["userAccountControl"] = MessageElement(
1611 #              str(UF_INTERDOMAIN_TRUST_ACCOUNT),
1612 #              FLAG_MOD_REPLACE, "userAccountControl")
1613 #            ldb.modify(m)
1614 #            self.fail()
1615 #        except LdbError, (num, _):
1616 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1617
1618         # With a computer object
1619
1620         # Add operation
1621
1622         # As computer you can set a normal account and a server trust account.
1623         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1624         # password yet.
1625         # With SYSTEM rights you can set a interdomain trust account.
1626
1627         # Invalid attribute
1628         try:
1629             ldb.add({
1630                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1631                 "objectclass": "computer",
1632                 "userAccountControl": "0"})
1633             self.fail()
1634         except LdbError, (num, _):
1635             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1636         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1637
1638 # This has to wait until s4 supports it (needs a password module change)
1639 #        try:
1640 #            ldb.add({
1641 #                "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1642 #                "objectclass": "computer",
1643 #                "userAccountControl": str(UF_NORMAL_ACCOUNT)})
1644 #            self.fail()
1645 #        except LdbError, (num, _):
1646 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1647 #        delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1648
1649         ldb.add({
1650             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1651             "objectclass": "computer",
1652             "userAccountControl": str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD)})
1653
1654         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1655                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1656         self.assertTrue(len(res1) == 1)
1657         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1658           ATYPE_NORMAL_ACCOUNT)
1659         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1660
1661         try:
1662             ldb.add({
1663                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1664                 "objectclass": "computer",
1665                 "userAccountControl": str(UF_TEMP_DUPLICATE_ACCOUNT)})
1666             self.fail()
1667         except LdbError, (num, _):
1668             self.assertEquals(num, ERR_OTHER)
1669         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1670
1671         ldb.add({
1672             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1673             "objectclass": "computer",
1674             "userAccountControl": str(UF_SERVER_TRUST_ACCOUNT)})
1675
1676         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1677                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1678         self.assertTrue(len(res1) == 1)
1679         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1680           ATYPE_WORKSTATION_TRUST)
1681         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1682
1683         try:
1684             ldb.add({
1685                 "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1686                 "objectclass": "computer",
1687                 "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT)})
1688         except LdbError, (num, _):
1689             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
1690         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1691
1692 # This isn't supported yet in s4 - needs ACL module adaption
1693 #        try:
1694 #            ldb.add({
1695 #                "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1696 #                "objectclass": "computer",
1697 #                "userAccountControl": str(UF_INTERDOMAIN_TRUST_ACCOUNT)})
1698 #            self.fail()
1699 #        except LdbError, (num, _):
1700 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1701 #        delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1702
1703         # Modify operation
1704
1705         ldb.add({
1706             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1707             "objectclass": "computer"})
1708
1709         # After creation we should have a normal account
1710         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1711                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1712         self.assertTrue(len(res1) == 1)
1713         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1714           ATYPE_NORMAL_ACCOUNT)
1715
1716         # As computer you can switch from a normal account to a workstation
1717         # or server trust account and back (also swapping between trust
1718         # accounts is allowed).
1719         # The UF_PASSWD_NOTREQD flag is needed since we haven't requested a
1720         # password yet.
1721         # With SYSTEM rights you can switch to a interdomain trust account.
1722
1723         # Invalid attribute
1724         try:
1725             m = Message()
1726             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1727             m["userAccountControl"] = MessageElement("0",
1728               FLAG_MOD_REPLACE, "userAccountControl")
1729             ldb.modify(m)
1730         except LdbError, (num, _):
1731             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1732
1733 # This has to wait until s4 supports it (needs a password module change)
1734 #        try:
1735 #            m = Message()
1736 #            m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1737 #            m["userAccountControl"] = MessageElement(
1738 #              str(UF_NORMAL_ACCOUNT),
1739 #              FLAG_MOD_REPLACE, "userAccountControl")
1740 #            ldb.modify(m)
1741 #        except LdbError, (num, _):
1742 #            self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1743
1744         m = Message()
1745         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1746         m["userAccountControl"] = MessageElement(
1747           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1748           FLAG_MOD_REPLACE, "userAccountControl")
1749         ldb.modify(m)
1750
1751         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1752                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1753         self.assertTrue(len(res1) == 1)
1754         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1755           ATYPE_NORMAL_ACCOUNT)
1756
1757         try:
1758             m = Message()
1759             m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1760             m["userAccountControl"] = MessageElement(
1761               str(UF_TEMP_DUPLICATE_ACCOUNT),
1762               FLAG_MOD_REPLACE, "userAccountControl")
1763             ldb.modify(m)
1764             self.fail()
1765         except LdbError, (num, _):
1766             self.assertEquals(num, ERR_OTHER)
1767
1768         m = Message()
1769         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1770         m["userAccountControl"] = MessageElement(
1771           str(UF_SERVER_TRUST_ACCOUNT),
1772           FLAG_MOD_REPLACE, "userAccountControl")
1773         ldb.modify(m)
1774
1775         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1776                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1777         self.assertTrue(len(res1) == 1)
1778         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1779           ATYPE_WORKSTATION_TRUST)
1780
1781         m = Message()
1782         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1783         m["userAccountControl"] = MessageElement(
1784           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1785           FLAG_MOD_REPLACE, "userAccountControl")
1786         ldb.modify(m)
1787
1788         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1789                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1790         self.assertTrue(len(res1) == 1)
1791         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1792           ATYPE_NORMAL_ACCOUNT)
1793
1794         m = Message()
1795         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1796         m["userAccountControl"] = MessageElement(
1797           str(UF_WORKSTATION_TRUST_ACCOUNT),
1798           FLAG_MOD_REPLACE, "userAccountControl")
1799         ldb.modify(m)
1800
1801         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1802                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1803         self.assertTrue(len(res1) == 1)
1804         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1805           ATYPE_WORKSTATION_TRUST)
1806
1807         m = Message()
1808         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1809         m["userAccountControl"] = MessageElement(
1810           str(UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD),
1811           FLAG_MOD_REPLACE, "userAccountControl")
1812         ldb.modify(m)
1813
1814         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1815                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1816         self.assertTrue(len(res1) == 1)
1817         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1818           ATYPE_NORMAL_ACCOUNT)
1819
1820         m = Message()
1821         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1822         m["userAccountControl"] = MessageElement(
1823           str(UF_SERVER_TRUST_ACCOUNT),
1824           FLAG_MOD_REPLACE, "userAccountControl")
1825         ldb.modify(m)
1826
1827         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1828                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1829         self.assertTrue(len(res1) == 1)
1830         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1831           ATYPE_WORKSTATION_TRUST)
1832
1833         m = Message()
1834         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1835         m["userAccountControl"] = MessageElement(
1836           str(UF_WORKSTATION_TRUST_ACCOUNT),
1837           FLAG_MOD_REPLACE, "userAccountControl")
1838         ldb.modify(m)
1839
1840         res1 = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1841                           scope=SCOPE_BASE, attrs=["sAMAccountType"])
1842         self.assertTrue(len(res1) == 1)
1843         self.assertEquals(int(res1[0]["sAMAccountType"][0]),
1844           ATYPE_WORKSTATION_TRUST)
1845
1846 # This isn't supported yet in s4 - needs ACL module adaption
1847 #        try:
1848 #            m = Message()
1849 #            m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1850 #            m["userAccountControl"] = MessageElement(
1851 #              str(UF_INTERDOMAIN_TRUST_ACCOUNT),
1852 #              FLAG_MOD_REPLACE, "userAccountControl")
1853 #            ldb.modify(m)
1854 #            self.fail()
1855 #        except LdbError, (num, _):
1856 #            self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
1857
1858         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1859         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1860
1861     def test_service_principal_name_updates(self):
1862         """Test the servicePrincipalNames update behaviour"""
1863         print "Testing servicePrincipalNames update behaviour\n"
1864
1865         ldb.add({
1866             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1867             "objectclass": "computer",
1868             "dNSHostName": "testname.testdom"})
1869
1870         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1871                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1872         self.assertTrue(len(res) == 1)
1873         self.assertFalse("servicePrincipalName" in res[0])
1874
1875         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1876
1877         ldb.add({
1878             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1879             "objectclass": "computer",
1880             "servicePrincipalName": "HOST/testname.testdom"})
1881
1882         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1883                           scope=SCOPE_BASE, attrs=["dNSHostName"])
1884         self.assertTrue(len(res) == 1)
1885         self.assertFalse("dNSHostName" in res[0])
1886
1887         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1888
1889         ldb.add({
1890             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1891             "objectclass": "computer",
1892             "dNSHostName": "testname2.testdom",
1893             "servicePrincipalName": "HOST/testname.testdom"})
1894
1895         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1896                          scope=SCOPE_BASE, attrs=["dNSHostName"])
1897         self.assertTrue(len(res) == 1)
1898         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
1899
1900         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1901                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1902         self.assertTrue(len(res) == 1)
1903         self.assertEquals(res[0]["servicePrincipalName"][0],
1904                           "HOST/testname.testdom")
1905
1906         m = Message()
1907         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1908         m["dNSHostName"] = MessageElement("testname.testdoM",
1909                                           FLAG_MOD_REPLACE, "dNSHostName")
1910         ldb.modify(m)
1911
1912         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1913                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1914         self.assertTrue(len(res) == 1)
1915         self.assertEquals(res[0]["servicePrincipalName"][0],
1916                           "HOST/testname.testdom")
1917
1918         m = Message()
1919         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1920         m["dNSHostName"] = MessageElement("testname2.testdom2",
1921                                           FLAG_MOD_REPLACE, "dNSHostName")
1922         ldb.modify(m)
1923
1924         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1925                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1926         self.assertTrue(len(res) == 1)
1927         self.assertEquals(res[0]["servicePrincipalName"][0],
1928                           "HOST/testname2.testdom2")
1929
1930         m = Message()
1931         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1932         m["dNSHostName"] = MessageElement([],
1933                                           FLAG_MOD_DELETE, "dNSHostName")
1934         ldb.modify(m)
1935
1936         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1937                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1938         self.assertTrue(len(res) == 1)
1939         self.assertEquals(res[0]["servicePrincipalName"][0],
1940                           "HOST/testname2.testdom2")
1941
1942         m = Message()
1943         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1944         m["dNSHostName"] = MessageElement("testname.testdom3",
1945                                           FLAG_MOD_REPLACE, "dNSHostName")
1946         ldb.modify(m)
1947
1948         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1949                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1950         self.assertTrue(len(res) == 1)
1951         self.assertEquals(res[0]["servicePrincipalName"][0],
1952                           "HOST/testname2.testdom2")
1953
1954         m = Message()
1955         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1956         m["dNSHostName"] = MessageElement("testname2.testdom2",
1957                                           FLAG_MOD_REPLACE, "dNSHostName")
1958         ldb.modify(m)
1959
1960         m = Message()
1961         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1962         m["dNSHostName"] = MessageElement("testname3.testdom3",
1963                                           FLAG_MOD_REPLACE, "dNSHostName")
1964         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom2",
1965                                                    FLAG_MOD_REPLACE,
1966                                                    "servicePrincipalName")
1967         ldb.modify(m)
1968
1969         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1970                           scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1971         self.assertTrue(len(res) == 1)
1972         self.assertEquals(res[0]["servicePrincipalName"][0],
1973                           "HOST/testname3.testdom3")
1974
1975         m = Message()
1976         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1977         m["servicePrincipalName"] = MessageElement("HOST/testname2.testdom2",
1978                                                    FLAG_MOD_REPLACE,
1979                                                    "servicePrincipalName")
1980         m["dNSHostName"] = MessageElement("testname4.testdom4",
1981                                           FLAG_MOD_REPLACE, "dNSHostName")
1982         ldb.modify(m)
1983
1984         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
1985                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
1986         self.assertTrue(len(res) == 1)
1987         self.assertEquals(res[0]["servicePrincipalName"][0],
1988                           "HOST/testname2.testdom2")
1989
1990         m = Message()
1991         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1992         m["servicePrincipalName"] = MessageElement([],
1993                                                    FLAG_MOD_DELETE,
1994                                                    "servicePrincipalName")
1995         ldb.modify(m)
1996
1997         m = Message()
1998         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
1999         m["dNSHostName"] = MessageElement("testname2.testdom2",
2000                                           FLAG_MOD_REPLACE, "dNSHostName")
2001         ldb.modify(m)
2002
2003         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2004                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2005         self.assertTrue(len(res) == 1)
2006         self.assertFalse("servicePrincipalName" in res[0])
2007
2008         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2009
2010         ldb.add({
2011             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2012             "objectclass": "computer",
2013             "sAMAccountName": "testname$"})
2014
2015         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2016                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2017         self.assertTrue(len(res) == 1)
2018         self.assertFalse("servicePrincipalName" in res[0])
2019
2020         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2021
2022         ldb.add({
2023             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2024             "objectclass": "computer",
2025             "servicePrincipalName": "HOST/testname"})
2026
2027         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2028                          scope=SCOPE_BASE, attrs=["sAMAccountName"])
2029         self.assertTrue(len(res) == 1)
2030         self.assertTrue("sAMAccountName" in res[0])
2031
2032         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2033
2034         ldb.add({
2035             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2036             "objectclass": "computer",
2037             "sAMAccountName": "testname$",
2038             "servicePrincipalName": "HOST/testname"})
2039
2040         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2041                          scope=SCOPE_BASE, attrs=["sAMAccountName"])
2042         self.assertTrue(len(res) == 1)
2043         self.assertEquals(res[0]["sAMAccountName"][0], "testname$")
2044
2045         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2046                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2047         self.assertTrue(len(res) == 1)
2048         self.assertEquals(res[0]["servicePrincipalName"][0],
2049                           "HOST/testname")
2050
2051         m = Message()
2052         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2053         m["sAMAccountName"] = MessageElement("testnamE$",
2054                                              FLAG_MOD_REPLACE, "sAMAccountName")
2055         ldb.modify(m)
2056
2057         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2058                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2059         self.assertTrue(len(res) == 1)
2060         self.assertEquals(res[0]["servicePrincipalName"][0],
2061                           "HOST/testname")
2062
2063         m = Message()
2064         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2065         m["sAMAccountName"] = MessageElement("testname",
2066                                              FLAG_MOD_REPLACE, "sAMAccountName")
2067         ldb.modify(m)
2068
2069         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2070                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2071         self.assertTrue(len(res) == 1)
2072         self.assertEquals(res[0]["servicePrincipalName"][0],
2073                           "HOST/testname")
2074
2075         m = Message()
2076         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2077         m["sAMAccountName"] = MessageElement("test$name$",
2078                                              FLAG_MOD_REPLACE, "sAMAccountName")
2079         ldb.modify(m)
2080
2081         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2082                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2083         self.assertTrue(len(res) == 1)
2084         self.assertEquals(res[0]["servicePrincipalName"][0],
2085                           "HOST/test$name")
2086
2087         m = Message()
2088         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2089         m["sAMAccountName"] = MessageElement("testname2",
2090                                              FLAG_MOD_REPLACE, "sAMAccountName")
2091         ldb.modify(m)
2092
2093         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2094                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2095         self.assertTrue(len(res) == 1)
2096         self.assertEquals(res[0]["servicePrincipalName"][0],
2097                           "HOST/testname2")
2098
2099         m = Message()
2100         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2101         m["sAMAccountName"] = MessageElement("testname3",
2102                                              FLAG_MOD_REPLACE, "sAMAccountName")
2103         m["servicePrincipalName"] = MessageElement("HOST/testname2",
2104                                                    FLAG_MOD_REPLACE,
2105                                                    "servicePrincipalName")
2106         ldb.modify(m)
2107
2108         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2109                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2110         self.assertTrue(len(res) == 1)
2111         self.assertEquals(res[0]["servicePrincipalName"][0],
2112                           "HOST/testname3")
2113
2114         m = Message()
2115         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2116         m["servicePrincipalName"] = MessageElement("HOST/testname2",
2117                                                    FLAG_MOD_REPLACE,
2118                                                    "servicePrincipalName")
2119         m["sAMAccountName"] = MessageElement("testname4",
2120                                              FLAG_MOD_REPLACE, "sAMAccountName")
2121         ldb.modify(m)
2122
2123         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2124                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2125         self.assertTrue(len(res) == 1)
2126         self.assertEquals(res[0]["servicePrincipalName"][0],
2127                           "HOST/testname2")
2128
2129         m = Message()
2130         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2131         m["servicePrincipalName"] = MessageElement([],
2132                                                    FLAG_MOD_DELETE,
2133                                                    "servicePrincipalName")
2134         ldb.modify(m)
2135
2136         m = Message()
2137         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2138         m["sAMAccountName"] = MessageElement("testname2",
2139                                              FLAG_MOD_REPLACE, "sAMAccountName")
2140         ldb.modify(m)
2141
2142         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2143                          scope=SCOPE_BASE, attrs=["servicePrincipalName"])
2144         self.assertTrue(len(res) == 1)
2145         self.assertFalse("servicePrincipalName" in res[0])
2146
2147         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2148
2149         ldb.add({
2150             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2151             "objectclass": "computer",
2152             "dNSHostName": "testname.testdom",
2153             "sAMAccountName": "testname$",
2154             "servicePrincipalName": [ "HOST/testname.testdom", "HOST/testname" ]
2155         })
2156
2157         m = Message()
2158         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2159         m["dNSHostName"] = MessageElement("testname2.testdom",
2160                                           FLAG_MOD_REPLACE, "dNSHostName")
2161         m["sAMAccountName"] = MessageElement("testname2$",
2162                                              FLAG_MOD_REPLACE, "sAMAccountName")
2163         ldb.modify(m)
2164
2165         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2166                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
2167         self.assertTrue(len(res) == 1)
2168         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
2169         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
2170         self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2" or
2171                         res[0]["servicePrincipalName"][1] == "HOST/testname2")
2172         self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2.testdom" or
2173                         res[0]["servicePrincipalName"][1] == "HOST/testname2.testdom")
2174
2175         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2176
2177         ldb.add({
2178             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
2179             "objectclass": "computer",
2180             "dNSHostName": "testname.testdom",
2181             "sAMAccountName": "testname$",
2182             "servicePrincipalName": [ "HOST/testname.testdom", "HOST/testname" ]
2183         })
2184
2185         m = Message()
2186         m.dn = Dn(ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2187         m["sAMAccountName"] = MessageElement("testname2$",
2188                                              FLAG_MOD_REPLACE, "sAMAccountName")
2189         m["dNSHostName"] = MessageElement("testname2.testdom",
2190                                           FLAG_MOD_REPLACE, "dNSHostName")
2191         ldb.modify(m)
2192
2193         res = ldb.search("cn=ldaptestcomputer,cn=computers," + self.base_dn,
2194                          scope=SCOPE_BASE, attrs=["dNSHostName", "sAMAccountName", "servicePrincipalName"])
2195         self.assertTrue(len(res) == 1)
2196         self.assertEquals(res[0]["dNSHostName"][0], "testname2.testdom")
2197         self.assertEquals(res[0]["sAMAccountName"][0], "testname2$")
2198         self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2" or
2199                         res[0]["servicePrincipalName"][1] == "HOST/testname2")
2200         self.assertTrue(res[0]["servicePrincipalName"][0] == "HOST/testname2.testdom" or
2201                         res[0]["servicePrincipalName"][1] == "HOST/testname2.testdom")
2202
2203         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2204
2205     def test_sam_description_attribute(self):
2206         """Test SAM description attribute"""
2207         print "Test SAM description attribute"""
2208
2209         self.ldb.add({
2210             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2211             "description": "desc2",
2212             "objectclass": "group",
2213             "description": "desc1"})
2214
2215         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2216                          scope=SCOPE_BASE, attrs=["description"])
2217         self.assertTrue(len(res) == 1)
2218         self.assertTrue("description" in res[0])
2219         self.assertTrue(len(res[0]["description"]) == 1)
2220         self.assertEquals(res[0]["description"][0], "desc1")
2221
2222         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2223
2224         self.ldb.add({
2225             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2226             "objectclass": "group",
2227             "description": ["desc1", "desc2"]})
2228
2229         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2230                          scope=SCOPE_BASE, attrs=["description"])
2231         self.assertTrue(len(res) == 1)
2232         self.assertTrue("description" in res[0])
2233         self.assertTrue(len(res[0]["description"]) == 2)
2234         self.assertTrue(res[0]["description"][0] == "desc1" or
2235                         res[0]["description"][1] == "desc1")
2236         self.assertTrue(res[0]["description"][0] == "desc2" or
2237                         res[0]["description"][1] == "desc2")
2238
2239         m = Message()
2240         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2241         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
2242           "description")
2243         try:
2244             ldb.modify(m)
2245             self.fail()
2246         except LdbError, (num, _):
2247             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2248
2249         m = Message()
2250         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2251         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
2252           "description")
2253         ldb.modify(m)
2254
2255         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2256
2257         self.ldb.add({
2258             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2259             "objectclass": "group" })
2260
2261         m = Message()
2262         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2263         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
2264           "description")
2265         ldb.modify(m)
2266
2267         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2268                          scope=SCOPE_BASE, attrs=["description"])
2269         self.assertTrue(len(res) == 1)
2270         self.assertTrue("description" in res[0])
2271         self.assertTrue(len(res[0]["description"]) == 1)
2272         self.assertEquals(res[0]["description"][0], "desc1")
2273
2274         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2275
2276         self.ldb.add({
2277             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
2278             "objectclass": "group",
2279             "description": ["desc1", "desc2"]})
2280
2281         m = Message()
2282         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2283         m["description"] = MessageElement("desc1", FLAG_MOD_REPLACE,
2284           "description")
2285         ldb.modify(m)
2286
2287         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2288                          scope=SCOPE_BASE, attrs=["description"])
2289         self.assertTrue(len(res) == 1)
2290         self.assertTrue("description" in res[0])
2291         self.assertTrue(len(res[0]["description"]) == 1)
2292         self.assertEquals(res[0]["description"][0], "desc1")
2293
2294         m = Message()
2295         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2296         m["description"] = MessageElement("desc3", FLAG_MOD_ADD,
2297           "description")
2298         try:
2299             ldb.modify(m)
2300             self.fail()
2301         except LdbError, (num, _):
2302             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2303
2304         m = Message()
2305         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2306         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_DELETE,
2307           "description")
2308         try:
2309             ldb.modify(m)
2310             self.fail()
2311         except LdbError, (num, _):
2312             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
2313
2314         m = Message()
2315         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2316         m["description"] = MessageElement("desc1", FLAG_MOD_DELETE,
2317           "description")
2318         ldb.modify(m)
2319         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2320                          scope=SCOPE_BASE, attrs=["description"])
2321         self.assertTrue(len(res) == 1)
2322         self.assertFalse("description" in res[0])
2323
2324         m = Message()
2325         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2326         m["description"] = MessageElement(["desc1","desc2"], FLAG_MOD_REPLACE,
2327           "description")
2328         try:
2329             ldb.modify(m)
2330             self.fail()
2331         except LdbError, (num, _):
2332             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2333
2334         m = Message()
2335         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2336         m["description"] = MessageElement(["desc3", "desc4"], FLAG_MOD_ADD,
2337           "description")
2338         try:
2339             ldb.modify(m)
2340             self.fail()
2341         except LdbError, (num, _):
2342             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
2343
2344         m = Message()
2345         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2346         m["description"] = MessageElement("desc1", FLAG_MOD_ADD,
2347           "description")
2348         ldb.modify(m)
2349
2350         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
2351                          scope=SCOPE_BASE, attrs=["description"])
2352         self.assertTrue(len(res) == 1)
2353         self.assertTrue("description" in res[0])
2354         self.assertTrue(len(res[0]["description"]) == 1)
2355         self.assertEquals(res[0]["description"][0], "desc1")
2356
2357         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2358
2359
2360 if not "://" in host:
2361     if os.path.isfile(host):
2362         host = "tdb://%s" % host
2363     else:
2364         host = "ldap://%s" % host
2365
2366 ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp)
2367
2368 runner = SubunitTestRunner()
2369 rc = 0
2370 if not runner.run(unittest.makeSuite(SamTests)).wasSuccessful():
2371     rc = 1
2372 sys.exit(rc)