Revert "pidl: Use non-existent function dissect_ndr_int64()"
[Samba.git] / python / samba / netcmd / dsacl.py
blob527c53482b698d3536f31a74c42e3da5420e631b
1 # Manipulate ACLs on directory objects
3 # Copyright (C) Nadezhda Ivanova <nivanova@samba.org> 2010
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 import samba.getopt as options
20 from samba import sd_utils
21 from samba.dcerpc import security
22 from samba.samdb import SamDB
23 from samba.ndr import ndr_unpack, ndr_pack
24 from samba.dcerpc.security import (
25 GUID_DRS_ALLOCATE_RIDS, GUID_DRS_CHANGE_DOMAIN_MASTER,
26 GUID_DRS_CHANGE_INFR_MASTER, GUID_DRS_CHANGE_PDC,
27 GUID_DRS_CHANGE_RID_MASTER, GUID_DRS_CHANGE_SCHEMA_MASTER,
28 GUID_DRS_GET_CHANGES, GUID_DRS_GET_ALL_CHANGES,
29 GUID_DRS_GET_FILTERED_ATTRIBUTES, GUID_DRS_MANAGE_TOPOLOGY,
30 GUID_DRS_MONITOR_TOPOLOGY, GUID_DRS_REPL_SYNCRONIZE,
31 GUID_DRS_RO_REPL_SECRET_SYNC)
34 import ldb
35 from ldb import SCOPE_BASE
36 import re
38 from samba.auth import system_session
39 from samba.netcmd import (
40 Command,
41 CommandError,
42 SuperCommand,
43 Option,
46 class cmd_dsacl_base(Command):
47 """Base class for DSACL commands."""
49 synopsis = "%prog [options]"
51 takes_optiongroups = {
52 "sambaopts": options.SambaOptions,
53 "credopts": options.CredentialsOptions,
54 "versionopts": options.VersionOptions,
57 def print_acl(self, sd_helper, object_dn, prefix=''):
58 desc_sddl = sd_helper.get_sd_as_sddl(object_dn)
59 self.outf.write("%sdescriptor for %s:\n" % (prefix, object_dn))
60 self.outf.write(desc_sddl + "\n")
63 class cmd_dsacl_set(cmd_dsacl_base):
64 """Modify access list on a directory object."""
66 car_help = """ The access control right to allow or deny """
68 takes_options = [
69 Option("-H", "--URL", help="LDB URL for database or target server",
70 type=str, metavar="URL", dest="H"),
71 Option("--car", type="choice", choices=["change-rid",
72 "change-pdc",
73 "change-infrastructure",
74 "change-schema",
75 "change-naming",
76 "allocate_rids",
77 "get-changes",
78 "get-changes-all",
79 "get-changes-filtered",
80 "topology-manage",
81 "topology-monitor",
82 "repl-sync",
83 "ro-repl-secret-sync"],
84 help=car_help),
85 Option("--action", type="choice", choices=["allow", "deny"],
86 help="""Deny or allow access"""),
87 Option("--objectdn", help="DN of the object whose SD to modify",
88 type="string"),
89 Option("--trusteedn", help="DN of the entity that gets access",
90 type="string"),
91 Option("--sddl", help="An ACE or group of ACEs to be added on the object",
92 type="string"),
95 def find_trustee_sid(self, samdb, trusteedn):
96 res = samdb.search(base=trusteedn, expression="(objectClass=*)",
97 scope=SCOPE_BASE)
98 assert(len(res) == 1)
99 return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
101 def add_ace(self, sd_helper, object_dn, new_ace):
102 """Add new ace explicitly."""
103 ai,ii = sd_helper.dacl_prepend_aces(object_dn, new_ace)
104 for ace in ii:
105 sddl = ace.as_sddl(sd_helper.domain_sid)
106 self.outf.write("WARNING: ignored INHERITED_ACE (%s).\n" % sddl)
107 for ace in ai:
108 sddl = ace.as_sddl(sd_helper.domain_sid)
109 self.outf.write("WARNING: (%s) was already found in the current security descriptor.\n" % sddl)
111 def run(self, car, action, objectdn, trusteedn, sddl,
112 H=None, credopts=None, sambaopts=None, versionopts=None):
113 lp = sambaopts.get_loadparm()
114 creds = credopts.get_credentials(lp)
116 if sddl is None and (car is None or action is None
117 or objectdn is None or trusteedn is None):
118 return self.usage()
120 samdb = SamDB(url=H, session_info=system_session(),
121 credentials=creds, lp=lp)
122 sd_helper = sd_utils.SDUtils(samdb)
123 cars = {'change-rid': GUID_DRS_CHANGE_RID_MASTER,
124 'change-pdc': GUID_DRS_CHANGE_PDC,
125 'change-infrastructure': GUID_DRS_CHANGE_INFR_MASTER,
126 'change-schema': GUID_DRS_CHANGE_SCHEMA_MASTER,
127 'change-naming': GUID_DRS_CHANGE_DOMAIN_MASTER,
128 'allocate_rids': GUID_DRS_ALLOCATE_RIDS,
129 'get-changes': GUID_DRS_GET_CHANGES,
130 'get-changes-all': GUID_DRS_GET_ALL_CHANGES,
131 'get-changes-filtered': GUID_DRS_GET_FILTERED_ATTRIBUTES,
132 'topology-manage': GUID_DRS_MANAGE_TOPOLOGY,
133 'topology-monitor': GUID_DRS_MONITOR_TOPOLOGY,
134 'repl-sync': GUID_DRS_REPL_SYNCRONIZE,
135 'ro-repl-secret-sync': GUID_DRS_RO_REPL_SECRET_SYNC,
137 sid = self.find_trustee_sid(samdb, trusteedn)
138 if sddl:
139 new_ace = sddl
140 elif action == "allow":
141 new_ace = "(OA;;CR;%s;;%s)" % (cars[car], str(sid))
142 elif action == "deny":
143 new_ace = "(OD;;CR;%s;;%s)" % (cars[car], str(sid))
144 else:
145 raise CommandError("Wrong argument '%s'!" % action)
147 self.print_acl(sd_helper, objectdn, prefix='old ')
148 self.add_ace(sd_helper, objectdn, new_ace)
149 self.print_acl(sd_helper, objectdn, prefix='new ')
152 class cmd_dsacl_get(cmd_dsacl_base):
153 """Print access list on a directory object."""
155 takes_options = [
156 Option("-H", "--URL", help="LDB URL for database or target server",
157 type=str, metavar="URL", dest="H"),
158 Option("--objectdn", help="DN of the object whose SD to modify",
159 type="string"),
162 def run(self, objectdn,
163 H=None, credopts=None, sambaopts=None, versionopts=None):
164 lp = sambaopts.get_loadparm()
165 creds = credopts.get_credentials(lp)
167 samdb = SamDB(url=H, session_info=system_session(),
168 credentials=creds, lp=lp)
169 sd_helper = sd_utils.SDUtils(samdb)
170 self.print_acl(sd_helper, objectdn)
173 class cmd_dsacl_delete(cmd_dsacl_base):
174 """Delete an access list entry on a directory object."""
176 takes_options = [
177 Option("-H", "--URL", help="LDB URL for database or target server",
178 type=str, metavar="URL", dest="H"),
179 Option("--objectdn", help="DN of the object whose SD to modify",
180 type="string"),
181 Option("--sddl", help="An ACE or group of ACEs to be deleted from the object",
182 type="string"),
185 def run(self, objectdn, sddl, H=None, credopts=None, sambaopts=None, versionopts=None):
186 lp = sambaopts.get_loadparm()
187 creds = credopts.get_credentials(lp)
189 if sddl is None or objectdn is None:
190 return self.usage()
192 samdb = SamDB(url=H, session_info=system_session(),
193 credentials=creds, lp=lp)
194 sd_helper = sd_utils.SDUtils(samdb)
196 self.print_acl(sd_helper, objectdn, prefix='old ')
197 self.delete_ace(sd_helper, objectdn, sddl)
198 self.print_acl(sd_helper, objectdn, prefix='new ')
200 def delete_ace(self, sd_helper, object_dn, delete_aces):
201 """Delete ace explicitly."""
202 di,ii = sd_helper.dacl_delete_aces(object_dn, delete_aces)
203 for ace in ii:
204 sddl = ace.as_sddl(sd_helper.domain_sid)
205 self.outf.write("WARNING: ignored INHERITED_ACE (%s).\n" % sddl)
206 for ace in di:
207 sddl = ace.as_sddl(sd_helper.domain_sid)
208 self.outf.write("WARNING: (%s) was not found in the current security descriptor.\n" % sddl)
211 class cmd_dsacl(SuperCommand):
212 """DS ACLs manipulation."""
214 subcommands = {}
215 subcommands["set"] = cmd_dsacl_set()
216 subcommands["get"] = cmd_dsacl_get()
217 subcommands["delete"] = cmd_dsacl_delete()