diff options
-rw-r--r-- | librpc/idl/security.idl | 19 | ||||
-rw-r--r-- | source4/scripting/python/pyglue.c | 15 | ||||
-rw-r--r-- | source4/scripting/python/samba/__init__.py | 15 | ||||
-rw-r--r-- | source4/scripting/python/samba/netcmd/__init__.py | 2 | ||||
-rw-r--r-- | source4/scripting/python/samba/netcmd/dsacl.py | 174 | ||||
-rw-r--r-- | source4/scripting/python/samba/netcmd/netacl.py | 36 | ||||
-rw-r--r-- | source4/scripting/python/samba/netcmd/ntacl.py | 2 |
7 files changed, 260 insertions, 3 deletions
diff --git a/librpc/idl/security.idl b/librpc/idl/security.idl index 186c2bcb6a..e7ae8541cc 100644 --- a/librpc/idl/security.idl +++ b/librpc/idl/security.idl @@ -479,4 +479,21 @@ interface security SEC_OWNER_FROM_PARENT = 0x00000008, SEC_GROUP_FROM_PARENT = 0x00000010 } security_autoinherit; -} + + /***************************************************************/ + /* Extended right guids */ + + const string GUID_DRS_ALLOCATE_RIDS = "1abd7cf8-0a99-11d1-adbb-00c04fd8d5cd"; + const string GUID_DRS_CHANGE_DOMAIN_MASTER = "014bf69c-7b3b-11d1-85f6-08002be74fab"; + const string GUID_DRS_CHANGE_INFR_MASTER = "cc17b1fb-33d9-11d2-97d4-00c04fd8d5cd"; + const string GUID_DRS_CHANGE_PDC = "bae50096-4752-11d1-9052-00c04fc2d4cf"; + const string GUID_DRS_CHANGE_RID_MASTER = "d58d5f36-0a98-11d1-adbb-00c04fd8d5cd"; + const string GUID_DRS_CHANGE_SCHEMA_MASTER = "e12b56b6-0a95-11d1-adbb-00c04fd8d5cd"; + const string GUID_DRS_GET_CHANGES = "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2"; + const string GUID_DRS_GET_ALL_CHANGES = "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"; + const string GUID_DRS_GET_FILTERED_ATTRIBUTES = "89e95b76-444d-4c62-991a-0facbeda640c"; + const string GUID_DRS_MANAGE_TOPOLOGY = "1131f6ac-9c07-11d1-f79f-00c04fc2dcd2"; + const string GUID_DRS_MONITOR_TOPOLOGY = "f98340fb-7c5b-4cdb-a00b-2ebdfa115a96"; + const string GUID_DRS_REPL_SYNCRONIZE = "1131f6ab-9c07-11d1-f79f-00c04fc2dcd2"; + const string GUID_DRS_RO_REPL_SECRET_SYNC = "1131f6ae-9c07-11d1-f79f-00c04fc2dcd2"; +}
\ No newline at end of file diff --git a/source4/scripting/python/pyglue.c b/source4/scripting/python/pyglue.c index c64f08e13e..e28406a0d6 100644 --- a/source4/scripting/python/pyglue.c +++ b/source4/scripting/python/pyglue.c @@ -772,6 +772,21 @@ void initglue(void) PyModule_AddObject(m, "SECINFO_DACL", PyInt_FromLong(SECINFO_DACL)); PyModule_AddObject(m, "SECINFO_SACL", PyInt_FromLong(SECINFO_SACL)); + /* control access rights guids */ + PyModule_AddObject(m, "GUID_DRS_ALLOCATE_RIDS", PyString_FromString(GUID_DRS_ALLOCATE_RIDS)); + PyModule_AddObject(m, "GUID_DRS_CHANGE_DOMAIN_MASTER", PyString_FromString(GUID_DRS_CHANGE_DOMAIN_MASTER)); + PyModule_AddObject(m, "GUID_DRS_CHANGE_INFR_MASTER", PyString_FromString(GUID_DRS_CHANGE_INFR_MASTER)); + PyModule_AddObject(m, "GUID_DRS_CHANGE_PDC", PyString_FromString(GUID_DRS_CHANGE_PDC)); + PyModule_AddObject(m, "GUID_DRS_CHANGE_RID_MASTER", PyString_FromString(GUID_DRS_CHANGE_RID_MASTER)); + PyModule_AddObject(m, "GUID_DRS_CHANGE_SCHEMA_MASTER", PyString_FromString(GUID_DRS_CHANGE_SCHEMA_MASTER)); + PyModule_AddObject(m, "GUID_DRS_GET_CHANGES", PyString_FromString(GUID_DRS_GET_CHANGES)); + PyModule_AddObject(m, "GUID_DRS_GET_ALL_CHANGES", PyString_FromString(GUID_DRS_GET_ALL_CHANGES)); + PyModule_AddObject(m, "GUID_DRS_GET_FILTERED_ATTRIBUTES", PyString_FromString(GUID_DRS_GET_FILTERED_ATTRIBUTES)); + PyModule_AddObject(m, "GUID_DRS_MANAGE_TOPOLOGY", PyString_FromString(GUID_DRS_MANAGE_TOPOLOGY)); + PyModule_AddObject(m, "GUID_DRS_MONITOR_TOPOLOGY", PyString_FromString(GUID_DRS_MONITOR_TOPOLOGY)); + PyModule_AddObject(m, "GUID_DRS_REPL_SYNCRONIZE", PyString_FromString(GUID_DRS_REPL_SYNCRONIZE)); + PyModule_AddObject(m, "GUID_DRS_RO_REPL_SECRET_SYNC", PyString_FromString(GUID_DRS_RO_REPL_SECRET_SYNC)); + /* one of the most annoying things about python scripts is that they don't die when you hit control-C. This fixes that sillyness. As we do all database operations using diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 9cc224b562..24bb45a003 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -442,3 +442,18 @@ SECINFO_GROUP = glue.SECINFO_GROUP SECINFO_DACL = glue.SECINFO_DACL SECINFO_SACL = glue.SECINFO_SACL +#control access rights guids +GUID_DRS_ALLOCATE_RIDS = glue.GUID_DRS_ALLOCATE_RIDS +GUID_DRS_CHANGE_DOMAIN_MASTER = glue.GUID_DRS_CHANGE_DOMAIN_MASTER +GUID_DRS_CHANGE_INFR_MASTER = glue.GUID_DRS_CHANGE_INFR_MASTER +GUID_DRS_CHANGE_PDC = glue.GUID_DRS_CHANGE_PDC +GUID_DRS_CHANGE_RID_MASTER = glue.GUID_DRS_CHANGE_RID_MASTER +GUID_DRS_CHANGE_SCHEMA_MASTER = glue.GUID_DRS_CHANGE_SCHEMA_MASTER +GUID_DRS_GET_CHANGES = glue.GUID_DRS_GET_CHANGES +GUID_DRS_GET_ALL_CHANGES = glue.GUID_DRS_GET_ALL_CHANGES +GUID_DRS_GET_FILTERED_ATTRIBUTES = glue.GUID_DRS_GET_FILTERED_ATTRIBUTES +GUID_DRS_MANAGE_TOPOLOGY = glue.GUID_DRS_MANAGE_TOPOLOGY +GUID_DRS_MONITOR_TOPOLOGY = glue.GUID_DRS_MONITOR_TOPOLOGY +GUID_DRS_REPL_SYNCRONIZE = glue.GUID_DRS_REPL_SYNCRONIZE +GUID_DRS_RO_REPL_SECRET_SYNC = glue.GUID_DRS_RO_REPL_SECRET_SYNC + diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index df0154ec4f..f09828e6bb 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -143,7 +143,7 @@ from samba.netcmd.enableaccount import cmd_enableaccount commands["enableaccount"] = cmd_enableaccount() from samba.netcmd.newuser import cmd_newuser commands["newuser"] = cmd_newuser() -from samba.netcmd.ntacl import cmd_acl +from samba.netcmd.netacl import cmd_acl commands["acl"] = cmd_acl() from samba.netcmd.fsmo import cmd_fsmo commands["fsmo"] = cmd_fsmo() diff --git a/source4/scripting/python/samba/netcmd/dsacl.py b/source4/scripting/python/samba/netcmd/dsacl.py new file mode 100644 index 0000000000..d5d39aa69a --- /dev/null +++ b/source4/scripting/python/samba/netcmd/dsacl.py @@ -0,0 +1,174 @@ +#!/usr/bin/python +# +# Manipulate ACLs on directory objects +# +# Copyright (C) Nadezhda Ivanova <nivanova@samba.org> 2010 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +from samba.credentials import DONT_USE_KERBEROS +import samba.getopt as options +from samba.dcerpc import security +from samba import Ldb +from samba.samdb import SamDB +from samba.ndr import ndr_unpack, ndr_pack +from samba import GUID_DRS_ALLOCATE_RIDS, GUID_DRS_CHANGE_DOMAIN_MASTER, \ + GUID_DRS_CHANGE_INFR_MASTER, GUID_DRS_CHANGE_PDC, GUID_DRS_CHANGE_RID_MASTER, \ + GUID_DRS_CHANGE_SCHEMA_MASTER, GUID_DRS_GET_CHANGES, GUID_DRS_GET_ALL_CHANGES, \ + GUID_DRS_GET_FILTERED_ATTRIBUTES, GUID_DRS_MANAGE_TOPOLOGY, \ + GUID_DRS_MONITOR_TOPOLOGY, GUID_DRS_REPL_SYNCRONIZE, GUID_DRS_RO_REPL_SECRET_SYNC + +import ldb +from ldb import SCOPE_BASE, SCOPE_SUBTREE +import os +import re + +from samba.auth import system_session +from samba.netcmd import ( + Command, + CommandError, + SuperCommand, + Option, + ) + +class cmd_ds_acl_set(Command): + """Modify access list on a directory object""" + + synopsis = "set --objectdn=objectdn --car=control right --action=[deny|allow] --trusteedn=trustee-dn" + car_help = """ The access control right to allow or deny """ + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "credopts": options.CredentialsOptions, + "versionopts": options.VersionOptions, + } + + takes_options = [ + Option("--host", help="LDB URL for database or target server", type=str), + Option("--car", type="choice", choices=["change-rid", + "change-pdc", + "change-infrastructure", + "change-schema", + "change-naming", + "allocate_rids", + "get-changes", + "get-changes-all", + "get-changes-filtered", + "topology-manage", + "topology-monitor", + "repl-sync", + "ro-repl-secret-sync"], + help=car_help), + Option("--action", type="choice", choices=["allow", "deny"], + help="""Deny or allow access"""), + Option("--objectdn", help="DN of the object whose SD to modify", type="string"), + Option("--trusteedn", help="DN of the entity that gets access", type="string"), + ] + + def find_trustee_sid(self, samdb, trusteedn): + res = samdb.search(base=trusteedn, expression="(objectClass=*)", scope=SCOPE_BASE) + assert(len(res) == 1) + return ndr_unpack( security.dom_sid,res[0]["objectSid"][0]) + + def modify_descriptor(self, samdb, object_dn, desc, controls=None): + assert(isinstance(desc, security.descriptor)) + m = ldb.Message() + m.dn = ldb.Dn(samdb, object_dn) + m["nTSecurityDescriptor"]= ldb.MessageElement( + (ndr_pack(desc)), ldb.FLAG_MOD_REPLACE, + "nTSecurityDescriptor") + samdb.modify(m) + + def read_descriptor(self, samdb, object_dn): + res = samdb.search(base=object_dn, scope=SCOPE_BASE, attrs=["nTSecurityDescriptor"]) + # we should theoretically always have an SD + assert(len(res) == 1) + desc = res[0]["nTSecurityDescriptor"][0] + return ndr_unpack(security.descriptor, desc) + + def get_domain_sid(self, samdb): + res = samdb.search(base=SamDB.domain_dn(samdb), expression="(objectClass=*)", scope=SCOPE_BASE) + return ndr_unpack( security.dom_sid,res[0]["objectSid"][0]) + + #add new ace explicitly + def add_ace(self, samdb, object_dn, new_ace): + desc = self.read_descriptor(samdb, object_dn) + desc_sddl = desc.as_sddl(self.get_domain_sid(samdb)) + #TODO add bindings for descriptor manipulation and get rid of this + desc_aces = re.findall("\(.*?\)", desc_sddl) + for ace in desc_aces: + if ("ID" in ace): + desc_sddl = desc_sddl.replace(ace, "") + if new_ace in desc_sddl: + return + if desc_sddl.find("(") >= 0: + desc_sddl = desc_sddl[:desc_sddl.index("(")] + new_ace + desc_sddl[desc_sddl.index("("):] + else: + desc_sddl = desc_sddl + new_ace + desc = security.descriptor.from_sddl(desc_sddl, self.get_domain_sid(samdb)) + self.modify_descriptor(samdb, object_dn, desc) + + def print_new_acl(self, samdb, object_dn): + desc = self.read_descriptor(samdb, object_dn) + desc_sddl = desc.as_sddl(self.get_domain_sid(samdb)) + print "new descriptor for %s:" % object_dn + print desc_sddl + + def run(self, car, action, objectdn, trusteedn, + host=None, credopts=None, sambaopts=None, versionopts=None): + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + + if car == None or action == None or objectdn == None or trusteedn == None: + return self.usage() + + if host is not None: + url = host + else: + url = lp.get("sam database") + + samdb = SamDB(url=url, session_info=system_session(), + credentials=creds, lp=lp) + cars = {'change-rid' : GUID_DRS_CHANGE_RID_MASTER, + 'change-pdc' : GUID_DRS_CHANGE_PDC, + 'change-infrastructure' : GUID_DRS_CHANGE_INFR_MASTER, + 'change-schema' : GUID_DRS_CHANGE_SCHEMA_MASTER, + 'change-naming' : GUID_DRS_CHANGE_DOMAIN_MASTER, + 'allocate_rids' : GUID_DRS_ALLOCATE_RIDS, + 'get-changes' : GUID_DRS_GET_CHANGES, + 'get-changes-all' : GUID_DRS_GET_ALL_CHANGES, + 'get-changes-filtered' : GUID_DRS_GET_FILTERED_ATTRIBUTES, + 'topology-manage' : GUID_DRS_MANAGE_TOPOLOGY, + 'topology-monitor' : GUID_DRS_MONITOR_TOPOLOGY, + 'repl-sync' : GUID_DRS_REPL_SYNCRONIZE, + 'ro-repl-secret-sync' : GUID_DRS_RO_REPL_SECRET_SYNC, + } + sid = self.find_trustee_sid(samdb, trusteedn) + if action == "allow": + new_ace = "(OA;;CR;%s;;%s)" % (cars[car], str(sid)) + elif action == "deny": + new_ace = "(OD;;CR;%s;;%s)" % (cars[car], str(sid)) + else: + raise CommandError("Wrong argument '%s'!" % action) + + self.print_new_acl(samdb, objectdn) + self.add_ace(samdb, objectdn, new_ace) + self.print_new_acl(samdb, objectdn) + +class cmd_ds_acl(SuperCommand): + """DS ACLs manipulation""" + + subcommands = {} + subcommands["set"] = cmd_ds_acl_set() diff --git a/source4/scripting/python/samba/netcmd/netacl.py b/source4/scripting/python/samba/netcmd/netacl.py new file mode 100644 index 0000000000..48e353a75f --- /dev/null +++ b/source4/scripting/python/samba/netcmd/netacl.py @@ -0,0 +1,36 @@ +#!/usr/bin/python +# +# Manipulate ACLs +# +# Copyright (C) Matthieu Patou <mat@matws.net> 2010 +# Copyright (C) Nadezhda Ivanova <nivanova@samba.org> 2010 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import samba.getopt as options +import os + +from samba.netcmd import ( + SuperCommand, + ) +from samba.netcmd.ntacl import cmd_nt_acl +from samba.netcmd.dsacl import cmd_ds_acl + +class cmd_acl(SuperCommand): + """NT ACLs manipulation""" + + subcommands = {} + subcommands["nt"] = cmd_nt_acl() + subcommands["ds"] = cmd_ds_acl() diff --git a/source4/scripting/python/samba/netcmd/ntacl.py b/source4/scripting/python/samba/netcmd/ntacl.py index 9b25ca2ba3..ebb66864d7 100644 --- a/source4/scripting/python/samba/netcmd/ntacl.py +++ b/source4/scripting/python/samba/netcmd/ntacl.py @@ -110,7 +110,7 @@ class cmd_acl_get(Command): acl.dump() -class cmd_acl(SuperCommand): +class cmd_nt_acl(SuperCommand): """NT ACLs manipulation""" subcommands = {} |