2010-03-16 14:06:08 +03:00
# 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/>.
#
import samba . getopt as options
from samba . dcerpc import security
from samba . samdb import SamDB
from samba . ndr import ndr_unpack , ndr_pack
2010-04-04 01:18:23 +04:00
from samba . dcerpc . security 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 )
2010-03-16 14:06:08 +03:00
import ldb
2010-04-04 01:18:23 +04:00
from ldb import SCOPE_BASE
2010-03-16 14:06:08 +03:00
import re
from samba . auth import system_session
from samba . netcmd import (
Command ,
CommandError ,
SuperCommand ,
Option ,
)
2011-08-31 01:09:53 +04:00
class cmd_dsacl_set ( Command ) :
2012-10-08 14:32:58 +04:00
""" Modify access list on a directory object. """
2010-03-16 14:06:08 +03:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog [options] "
2010-03-16 14:06:08 +03:00
car_help = """ The access control right to allow or deny """
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
}
2010-03-16 14:06:08 +03:00
takes_options = [
2011-07-25 19:56:10 +04:00
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
2010-03-16 14:06:08 +03:00
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 """ ) ,
2010-04-08 20:57:09 +04:00
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 " ) ,
2011-02-10 16:04:23 +03:00
Option ( " --sddl " , help = " An ACE or group of ACEs to be added on the object " ,
type = " string " ) ,
2010-03-16 14:06:08 +03:00
]
def find_trustee_sid ( self , samdb , trusteedn ) :
2010-04-08 20:57:09 +04:00
res = samdb . search ( base = trusteedn , expression = " (objectClass=*) " ,
scope = SCOPE_BASE )
2010-03-16 14:06:08 +03:00
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 ) :
2010-04-08 20:57:09 +04:00
res = samdb . search ( base = object_dn , scope = SCOPE_BASE ,
attrs = [ " nTSecurityDescriptor " ] )
2010-03-16 14:06:08 +03:00
# 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 ) :
2010-04-09 01:18:17 +04:00
res = samdb . search ( base = samdb . domain_dn ( ) ,
2010-04-08 20:57:09 +04:00
expression = " (objectClass=*) " , scope = SCOPE_BASE )
2010-03-16 14:06:08 +03:00
return ndr_unpack ( security . dom_sid , res [ 0 ] [ " objectSid " ] [ 0 ] )
def add_ace ( self , samdb , object_dn , new_ace ) :
2010-04-08 20:57:09 +04:00
""" Add new ace explicitly. """
2010-03-16 14:06:08 +03:00
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 ) )
2011-10-13 02:36:44 +04:00
self . outf . write ( " new descriptor for %s : \n " % object_dn )
self . outf . write ( desc_sddl + " \n " )
2010-03-16 14:06:08 +03:00
2011-02-10 16:04:23 +03:00
def run ( self , car , action , objectdn , trusteedn , sddl ,
2011-07-25 19:56:10 +04:00
H = None , credopts = None , sambaopts = None , versionopts = None ) :
2010-03-16 14:06:08 +03:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
2011-02-10 16:04:23 +03:00
if sddl is None and ( car is None or action is None
or objectdn is None or trusteedn is None ) :
2010-03-16 14:06:08 +03:00
return self . usage ( )
2011-07-25 19:56:10 +04:00
samdb = SamDB ( url = H , session_info = system_session ( ) ,
2010-03-16 14:06:08 +03:00
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 )
2011-02-10 16:04:23 +03:00
if sddl :
new_ace = sddl
elif action == " allow " :
2010-03-16 14:06:08 +03:00
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 )
2010-04-08 20:57:09 +04:00
2011-08-31 01:09:53 +04:00
class cmd_dsacl ( SuperCommand ) :
2012-10-09 13:53:21 +04:00
""" DS ACLs manipulation. """
2010-03-16 14:06:08 +03:00
subcommands = { }
2011-08-31 01:09:53 +04:00
subcommands [ " set " ] = cmd_dsacl_set ( )