libds:common Remove DS_DC_* domain functionality flags
[Samba/gebeck_regimport.git] / source4 / scripting / python / samba / netcmd / dsacl.py
blob0149d375be07a9469f5ca977d481250996fa202a
1 #!/usr/bin/python
3 # Manipulate ACLs on directory objects
5 # Copyright (C) Nadezhda Ivanova <nivanova@samba.org> 2010
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 import samba.getopt as options
22 from samba.dcerpc import security
23 from samba.samdb import SamDB
24 from samba.ndr import ndr_unpack, ndr_pack
25 from samba.dcerpc.security import (
26 GUID_DRS_ALLOCATE_RIDS, GUID_DRS_CHANGE_DOMAIN_MASTER,
27 GUID_DRS_CHANGE_INFR_MASTER, GUID_DRS_CHANGE_PDC,
28 GUID_DRS_CHANGE_RID_MASTER, GUID_DRS_CHANGE_SCHEMA_MASTER,
29 GUID_DRS_GET_CHANGES, GUID_DRS_GET_ALL_CHANGES,
30 GUID_DRS_GET_FILTERED_ATTRIBUTES, GUID_DRS_MANAGE_TOPOLOGY,
31 GUID_DRS_MONITOR_TOPOLOGY, GUID_DRS_REPL_SYNCRONIZE,
32 GUID_DRS_RO_REPL_SECRET_SYNC)
35 import ldb
36 from ldb import SCOPE_BASE
37 import re
39 from samba.auth import system_session
40 from samba.netcmd import (
41 Command,
42 CommandError,
43 SuperCommand,
44 Option,
47 class cmd_ds_acl_set(Command):
48 """Modify access list on a directory object"""
50 synopsis = "set --objectdn=objectdn --car=control right --action=[deny|allow] --trusteedn=trustee-dn"
51 car_help = """ The access control right to allow or deny """
53 takes_optiongroups = {
54 "sambaopts": options.SambaOptions,
55 "credopts": options.CredentialsOptions,
56 "versionopts": options.VersionOptions,
59 takes_options = [
60 Option("--host", help="LDB URL for database or target server",
61 type=str),
62 Option("--car", type="choice", choices=["change-rid",
63 "change-pdc",
64 "change-infrastructure",
65 "change-schema",
66 "change-naming",
67 "allocate_rids",
68 "get-changes",
69 "get-changes-all",
70 "get-changes-filtered",
71 "topology-manage",
72 "topology-monitor",
73 "repl-sync",
74 "ro-repl-secret-sync"],
75 help=car_help),
76 Option("--action", type="choice", choices=["allow", "deny"],
77 help="""Deny or allow access"""),
78 Option("--objectdn", help="DN of the object whose SD to modify",
79 type="string"),
80 Option("--trusteedn", help="DN of the entity that gets access",
81 type="string"),
84 def find_trustee_sid(self, samdb, trusteedn):
85 res = samdb.search(base=trusteedn, expression="(objectClass=*)",
86 scope=SCOPE_BASE)
87 assert(len(res) == 1)
88 return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
90 def modify_descriptor(self, samdb, object_dn, desc, controls=None):
91 assert(isinstance(desc, security.descriptor))
92 m = ldb.Message()
93 m.dn = ldb.Dn(samdb, object_dn)
94 m["nTSecurityDescriptor"]= ldb.MessageElement(
95 (ndr_pack(desc)), ldb.FLAG_MOD_REPLACE,
96 "nTSecurityDescriptor")
97 samdb.modify(m)
99 def read_descriptor(self, samdb, object_dn):
100 res = samdb.search(base=object_dn, scope=SCOPE_BASE,
101 attrs=["nTSecurityDescriptor"])
102 # we should theoretically always have an SD
103 assert(len(res) == 1)
104 desc = res[0]["nTSecurityDescriptor"][0]
105 return ndr_unpack(security.descriptor, desc)
107 def get_domain_sid(self, samdb):
108 res = samdb.search(base=samdb.domain_dn(),
109 expression="(objectClass=*)", scope=SCOPE_BASE)
110 return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
112 def add_ace(self, samdb, object_dn, new_ace):
113 """Add new ace explicitly."""
114 desc = self.read_descriptor(samdb, object_dn)
115 desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
116 #TODO add bindings for descriptor manipulation and get rid of this
117 desc_aces = re.findall("\(.*?\)", desc_sddl)
118 for ace in desc_aces:
119 if ("ID" in ace):
120 desc_sddl = desc_sddl.replace(ace, "")
121 if new_ace in desc_sddl:
122 return
123 if desc_sddl.find("(") >= 0:
124 desc_sddl = desc_sddl[:desc_sddl.index("(")] + new_ace + desc_sddl[desc_sddl.index("("):]
125 else:
126 desc_sddl = desc_sddl + new_ace
127 desc = security.descriptor.from_sddl(desc_sddl, self.get_domain_sid(samdb))
128 self.modify_descriptor(samdb, object_dn, desc)
130 def print_new_acl(self, samdb, object_dn):
131 desc = self.read_descriptor(samdb, object_dn)
132 desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
133 print "new descriptor for %s:" % object_dn
134 print desc_sddl
136 def run(self, car, action, objectdn, trusteedn,
137 host=None, credopts=None, sambaopts=None, versionopts=None):
138 lp = sambaopts.get_loadparm()
139 creds = credopts.get_credentials(lp)
141 if (car is None or action is None or objectdn is None or
142 trusteedn is None):
143 return self.usage()
145 samdb = SamDB(url=host, session_info=system_session(),
146 credentials=creds, lp=lp)
147 cars = {'change-rid' : GUID_DRS_CHANGE_RID_MASTER,
148 'change-pdc' : GUID_DRS_CHANGE_PDC,
149 'change-infrastructure' : GUID_DRS_CHANGE_INFR_MASTER,
150 'change-schema' : GUID_DRS_CHANGE_SCHEMA_MASTER,
151 'change-naming' : GUID_DRS_CHANGE_DOMAIN_MASTER,
152 'allocate_rids' : GUID_DRS_ALLOCATE_RIDS,
153 'get-changes' : GUID_DRS_GET_CHANGES,
154 'get-changes-all' : GUID_DRS_GET_ALL_CHANGES,
155 'get-changes-filtered' : GUID_DRS_GET_FILTERED_ATTRIBUTES,
156 'topology-manage' : GUID_DRS_MANAGE_TOPOLOGY,
157 'topology-monitor' : GUID_DRS_MONITOR_TOPOLOGY,
158 'repl-sync' : GUID_DRS_REPL_SYNCRONIZE,
159 'ro-repl-secret-sync' : GUID_DRS_RO_REPL_SECRET_SYNC,
161 sid = self.find_trustee_sid(samdb, trusteedn)
162 if action == "allow":
163 new_ace = "(OA;;CR;%s;;%s)" % (cars[car], str(sid))
164 elif action == "deny":
165 new_ace = "(OD;;CR;%s;;%s)" % (cars[car], str(sid))
166 else:
167 raise CommandError("Wrong argument '%s'!" % action)
169 self.print_new_acl(samdb, objectdn)
170 self.add_ace(samdb, objectdn, new_ace)
171 self.print_new_acl(samdb, objectdn)
174 class cmd_ds_acl(SuperCommand):
175 """DS ACLs manipulation"""
177 subcommands = {}
178 subcommands["set"] = cmd_ds_acl_set()