2011-06-24 18:59:24 +04:00
# delegation management
#
# Copyright Matthieu Patou mat@samba.org 2010
# Copyright Stefan Metzmacher metze@samba.org 2011
# Copyright Bjoern Baumbach bb@sernet.de 2011
#
# 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 ldb
from samba import provision
from samba import dsdb
from samba . samdb import SamDB
from samba . auth import system_session
2022-02-21 04:56:45 +03:00
from samba . dcerpc import security
2022-02-21 04:58:30 +03:00
from samba . ndr import ndr_pack , ndr_unpack
2011-09-07 19:11:38 +04:00
from samba . netcmd . common import _get_user_realm_domain
2011-06-24 18:59:24 +04:00
from samba . netcmd import (
Command ,
CommandError ,
SuperCommand ,
Option
2018-07-30 09:14:37 +03:00
)
2011-06-24 18:59:24 +04:00
2011-09-02 21:10:05 +04:00
2011-06-24 18:59:24 +04:00
class cmd_delegation_show ( Command ) :
""" Show the delegation setting of an account. """
2011-10-14 01:27:22 +04:00
2011-10-21 19:35:36 +04:00
synopsis = " % prog <accountname> [options] "
2011-06-24 18:59:24 +04:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2012-02-06 19:33:38 +04:00
2013-09-22 22:24:57 +04:00
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " , type = str ,
metavar = " URL " , dest = " H " ) ,
2018-07-30 09:14:37 +03:00
]
2013-09-22 22:24:57 +04:00
2011-06-24 18:59:24 +04:00
takes_args = [ " accountname " ]
2022-02-21 04:56:45 +03:00
def show_security_descriptor ( self , sam , security_descriptor ) :
dacl = security_descriptor . dacl
desc_type = security_descriptor . type
warning_info = ( ' Security Descriptor of attribute '
' msDS-AllowedToActOnBehalfOfOtherIdentity ' )
if dacl is None or not desc_type & security . SEC_DESC_DACL_PRESENT :
self . errf . write ( f ' Warning: DACL not present in { warning_info } ! \n ' )
return
if not desc_type & security . SEC_DESC_SELF_RELATIVE :
self . errf . write ( f ' Warning: DACL in { warning_info } lacks '
f ' SELF_RELATIVE flag! \n ' )
return
2022-02-21 05:07:50 +03:00
first = True
2022-02-21 04:56:45 +03:00
for ace in dacl . aces :
trustee = ace . trustee
# Convert the trustee SID into a DN if we can.
try :
res = sam . search ( f ' <SID= { trustee } > ' ,
scope = ldb . SCOPE_BASE )
except ldb . LdbError as err :
num , _ = err . args
if num != ldb . ERR_NO_SUCH_OBJECT :
raise
else :
if len ( res ) == 1 :
trustee = res [ 0 ] . dn
ignore = False
if ( ace . type == security . SEC_ACE_TYPE_ACCESS_DENIED
or ace . type == security . SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ) :
self . errf . write ( f ' Warning: ACE in { warning_info } denies '
f ' access for trustee { trustee } ! \n ' )
# Ignore the ACE if it denies access
ignore = True
elif ( ace . type != security . SEC_ACE_TYPE_ACCESS_ALLOWED
and ace . type != security . SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ) :
# Ignore the ACE if it doesn't explicitly allow access
ignore = True
inherit_only = ace . flags & security . SEC_ACE_FLAG_INHERIT_ONLY
object_inherit = ace . flags & security . SEC_ACE_FLAG_OBJECT_INHERIT
container_inherit = (
ace . flags & security . SEC_ACE_FLAG_CONTAINER_INHERIT )
inherited_ace = ace . flags & security . SEC_ACE_FLAG_INHERITED_ACE
if inherit_only and not object_inherit and not container_inherit :
# Ignore the ACE if it is propagated only to child objects, but
# neither of the object and container inherit flags are set.
ignore = True
else :
if container_inherit :
self . errf . write ( f ' Warning: ACE for trustee { trustee } has '
f ' unexpected CONTAINER_INHERIT flag set in '
f ' { warning_info } ! \n ' )
ignore = True
if inherited_ace :
self . errf . write ( f ' Warning: ACE for trustee { trustee } has '
f ' unexpected INHERITED_ACE flag set in '
f ' { warning_info } ! \n ' )
ignore = True
if not ace . access_mask :
# Ignore the ACE if it doesn't grant any permissions.
ignore = True
if not ignore :
2022-02-21 05:07:50 +03:00
if first :
2023-10-02 06:03:59 +03:00
self . outf . write ( ' Principals that may delegate to this '
' account: \n ' )
2022-02-21 05:07:50 +03:00
first = False
2022-02-21 04:56:45 +03:00
self . outf . write ( f ' msDS-AllowedToActOnBehalfOfOtherIdentity: '
f ' { trustee } \n ' )
2013-09-22 22:24:57 +04:00
def run ( self , accountname , H = None , credopts = None , sambaopts = None , versionopts = None ) :
2011-06-24 18:59:24 +04:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
2013-09-22 22:24:57 +04:00
2018-07-30 09:22:15 +03:00
if H is None :
2024-02-12 06:02:22 +03:00
paths = provision . provision_paths_from_lp ( lp , lp . get ( " realm " ) )
2013-09-22 22:24:57 +04:00
path = paths . samdb
else :
path = H
sam = SamDB ( path , session_info = system_session ( ) ,
2011-06-24 18:59:24 +04:00
credentials = creds , lp = lp )
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
( cleanedaccount , realm , domain ) = _get_user_realm_domain ( accountname ,
sam )
2012-09-16 16:18:39 +04:00
2012-09-27 20:30:47 +04:00
res = sam . search ( expression = " sAMAccountName= %s " %
2018-07-30 09:16:12 +03:00
ldb . binary_encode ( cleanedaccount ) ,
scope = ldb . SCOPE_SUBTREE ,
2022-02-21 05:07:50 +03:00
attrs = [ " userAccountControl " , " msDS-AllowedToDelegateTo " ,
" msDS-AllowedToActOnBehalfOfOtherIdentity " ] )
2011-10-21 19:49:29 +04:00
if len ( res ) == 0 :
raise CommandError ( " Unable to find account name ' %s ' " % accountname )
2024-02-12 06:13:13 +03:00
elif len ( res ) != 1 :
raise CommandError ( " Found multiple accounts. " )
2012-09-16 16:18:39 +04:00
2011-06-24 18:59:24 +04:00
uac = int ( res [ 0 ] . get ( " userAccountControl " ) [ 0 ] )
allowed = res [ 0 ] . get ( " msDS-AllowedToDelegateTo " )
2022-02-21 05:07:50 +03:00
allowed_from = res [ 0 ] . get ( " msDS-AllowedToActOnBehalfOfOtherIdentity " , idx = 0 )
2011-06-24 18:59:24 +04:00
2018-07-30 09:17:44 +03:00
self . outf . write ( " Account-DN: %s \n " % str ( res [ 0 ] . dn ) )
2011-10-13 02:19:51 +04:00
self . outf . write ( " UF_TRUSTED_FOR_DELEGATION: %s \n "
2018-07-30 09:16:12 +03:00
% bool ( uac & dsdb . UF_TRUSTED_FOR_DELEGATION ) )
2011-10-13 02:19:51 +04:00
self . outf . write ( " UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION: %s \n " %
2018-07-30 09:16:12 +03:00
bool ( uac & dsdb . UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION ) )
2011-06-24 18:59:24 +04:00
2022-02-21 05:07:50 +03:00
if allowed :
self . outf . write ( " Services this account may delegate to: \n " )
2011-06-24 18:59:24 +04:00
for a in allowed :
2011-10-13 02:19:51 +04:00
self . outf . write ( " msDS-AllowedToDelegateTo: %s \n " % a )
2022-02-21 05:07:50 +03:00
if allowed_from is not None :
try :
security_descriptor = ndr_unpack ( security . descriptor , allowed_from )
except RuntimeError :
self . errf . write ( " Warning: Security Descriptor of attribute "
" msDS-AllowedToActOnBehalfOfOtherIdentity "
" could not be unmarshalled! \n " )
else :
self . show_security_descriptor ( sam , security_descriptor )
2011-06-24 18:59:24 +04:00
2011-09-02 21:10:05 +04:00
2011-06-24 18:59:24 +04:00
class cmd_delegation_for_any_service ( Command ) :
""" Set/unset UF_TRUSTED_FOR_DELEGATION for an account. """
2011-09-02 21:10:05 +04:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog <accountname> [(on|off)] [options] "
2011-06-24 18:59:24 +04:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2012-02-06 19:33:38 +04:00
2013-09-22 22:24:57 +04:00
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " , type = str ,
metavar = " URL " , dest = " H " ) ,
2018-07-30 09:14:37 +03:00
]
2013-09-22 22:24:57 +04:00
2011-06-24 18:59:24 +04:00
takes_args = [ " accountname " , " onoff " ]
2013-09-22 22:24:57 +04:00
def run ( self , accountname , onoff , H = None , credopts = None , sambaopts = None ,
2012-09-16 16:18:39 +04:00
versionopts = None ) :
2011-06-24 18:59:24 +04:00
if onoff == " on " :
on = True
elif onoff == " off " :
on = False
else :
2011-10-21 19:57:34 +04:00
raise CommandError ( " invalid argument: ' %s ' (choose from ' on ' , ' off ' ) " % onoff )
2011-06-24 18:59:24 +04:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
paths = provision . provision_paths_from_lp ( lp , lp . get ( " realm " ) )
2018-07-30 09:22:15 +03:00
if H is None :
2013-09-22 22:24:57 +04:00
path = paths . samdb
else :
path = H
sam = SamDB ( path , session_info = system_session ( ) ,
2011-06-24 18:59:24 +04:00
credentials = creds , lp = lp )
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
( cleanedaccount , realm , domain ) = _get_user_realm_domain ( accountname ,
sam )
2011-06-24 18:59:24 +04:00
2011-09-13 02:19:45 +04:00
search_filter = " sAMAccountName= %s " % ldb . binary_encode ( cleanedaccount )
2011-06-24 18:59:24 +04:00
flag = dsdb . UF_TRUSTED_FOR_DELEGATION
try :
2011-10-21 20:05:07 +04:00
sam . toggle_userAccountFlags ( search_filter , flag ,
flags_str = " Trusted-for-Delegation " ,
on = on , strict = True )
2018-02-14 00:07:23 +03:00
except Exception as err :
2011-06-24 18:59:24 +04:00
raise CommandError ( err )
2011-09-02 21:10:05 +04:00
2011-06-24 18:59:24 +04:00
class cmd_delegation_for_any_protocol ( Command ) :
""" Set/unset UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION (S4U2Proxy) for an account. """
2011-09-02 21:10:05 +04:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog <accountname> [(on|off)] [options] "
2011-06-24 18:59:24 +04:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2012-02-06 19:33:38 +04:00
2013-09-22 22:24:57 +04:00
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " , type = str ,
metavar = " URL " , dest = " H " ) ,
2018-07-30 09:14:37 +03:00
]
2013-09-22 22:24:57 +04:00
2011-06-24 18:59:24 +04:00
takes_args = [ " accountname " , " onoff " ]
2013-09-22 22:24:57 +04:00
def run ( self , accountname , onoff , H = None , credopts = None , sambaopts = None ,
2012-09-16 16:18:39 +04:00
versionopts = None ) :
2011-06-24 18:59:24 +04:00
on = False
if onoff == " on " :
on = True
elif onoff == " off " :
on = False
else :
2011-10-21 19:57:34 +04:00
raise CommandError ( " invalid argument: ' %s ' (choose from ' on ' , ' off ' ) " % onoff )
2011-06-24 18:59:24 +04:00
lp = sambaopts . get_loadparm ( )
2013-09-22 22:24:57 +04:00
creds = credopts . get_credentials ( lp , fallback_machine = True )
2011-06-24 18:59:24 +04:00
paths = provision . provision_paths_from_lp ( lp , lp . get ( " realm " ) )
2018-07-30 09:22:15 +03:00
if H is None :
2013-09-22 22:24:57 +04:00
path = paths . samdb
else :
path = H
sam = SamDB ( path , session_info = system_session ( ) ,
2011-06-24 18:59:24 +04:00
credentials = creds , lp = lp )
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
( cleanedaccount , realm , domain ) = _get_user_realm_domain ( accountname ,
sam )
2011-06-24 18:59:24 +04:00
2011-09-13 02:19:45 +04:00
search_filter = " sAMAccountName= %s " % ldb . binary_encode ( cleanedaccount )
2011-06-24 18:59:24 +04:00
flag = dsdb . UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
try :
2011-10-21 20:05:07 +04:00
sam . toggle_userAccountFlags ( search_filter , flag ,
2018-07-30 09:16:12 +03:00
flags_str = " Trusted-to-Authenticate-for-Delegation " ,
on = on , strict = True )
2018-02-14 00:07:23 +03:00
except Exception as err :
2011-06-24 18:59:24 +04:00
raise CommandError ( err )
2011-09-02 21:10:05 +04:00
2011-06-24 18:59:24 +04:00
class cmd_delegation_add_service ( Command ) :
2022-02-21 04:58:47 +03:00
""" Add a service principal to msDS-AllowedToDelegateTo so that an account may delegate to it. """
2011-09-02 21:10:05 +04:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog <accountname> <principal> [options] "
2011-06-24 18:59:24 +04:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2012-02-06 19:33:38 +04:00
2013-09-22 22:24:57 +04:00
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " , type = str ,
metavar = " URL " , dest = " H " ) ,
2018-07-30 09:14:37 +03:00
]
2013-09-22 22:24:57 +04:00
2011-06-24 18:59:24 +04:00
takes_args = [ " accountname " , " principal " ]
2013-09-22 22:24:57 +04:00
def run ( self , accountname , principal , H = None , credopts = None , sambaopts = None ,
2012-09-16 16:18:39 +04:00
versionopts = None ) :
2011-06-24 18:59:24 +04:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
paths = provision . provision_paths_from_lp ( lp , lp . get ( " realm " ) )
2018-07-30 09:22:15 +03:00
if H is None :
2013-09-22 22:24:57 +04:00
path = paths . samdb
else :
path = H
sam = SamDB ( path , session_info = system_session ( ) ,
2011-06-24 18:59:24 +04:00
credentials = creds , lp = lp )
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
( cleanedaccount , realm , domain ) = _get_user_realm_domain ( accountname ,
sam )
2011-06-24 18:59:24 +04:00
2012-09-27 20:30:47 +04:00
res = sam . search ( expression = " sAMAccountName= %s " %
2011-10-21 19:49:29 +04:00
ldb . binary_encode ( cleanedaccount ) ,
scope = ldb . SCOPE_SUBTREE ,
attrs = [ " msDS-AllowedToDelegateTo " ] )
if len ( res ) == 0 :
raise CommandError ( " Unable to find account name ' %s ' " % accountname )
2024-02-12 06:13:13 +03:00
elif len ( res ) != 1 :
raise CommandError ( " Found multiple accounts. " )
2011-06-24 18:59:24 +04:00
msg = ldb . Message ( )
msg . dn = res [ 0 ] . dn
msg [ " msDS-AllowedToDelegateTo " ] = ldb . MessageElement ( [ principal ] ,
2018-07-30 09:16:12 +03:00
ldb . FLAG_MOD_ADD ,
" msDS-AllowedToDelegateTo " )
2011-06-24 18:59:24 +04:00
try :
sam . modify ( msg )
2018-02-14 00:07:23 +03:00
except Exception as err :
2011-06-24 18:59:24 +04:00
raise CommandError ( err )
2011-09-02 21:10:05 +04:00
2011-06-24 18:59:24 +04:00
class cmd_delegation_del_service ( Command ) :
2022-02-21 04:58:47 +03:00
""" Delete a service principal from msDS-AllowedToDelegateTo so that an account may no longer delegate to it. """
2011-09-02 21:10:05 +04:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog <accountname> <principal> [options] "
2011-06-24 18:59:24 +04:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
2018-07-30 09:14:37 +03:00
}
2012-02-06 19:33:38 +04:00
2013-09-22 22:24:57 +04:00
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " , type = str ,
metavar = " URL " , dest = " H " ) ,
2018-07-30 09:14:37 +03:00
]
2013-09-22 22:24:57 +04:00
2011-06-24 18:59:24 +04:00
takes_args = [ " accountname " , " principal " ]
2013-09-22 22:24:57 +04:00
def run ( self , accountname , principal , H = None , credopts = None , sambaopts = None ,
2012-09-16 16:18:39 +04:00
versionopts = None ) :
2011-06-24 18:59:24 +04:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
paths = provision . provision_paths_from_lp ( lp , lp . get ( " realm " ) )
2018-07-30 09:22:15 +03:00
if H is None :
2013-09-22 22:24:57 +04:00
path = paths . samdb
else :
path = H
sam = SamDB ( path , session_info = system_session ( ) ,
2011-06-24 18:59:24 +04:00
credentials = creds , lp = lp )
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
( cleanedaccount , realm , domain ) = _get_user_realm_domain ( accountname ,
sam )
2011-06-24 18:59:24 +04:00
2012-09-27 20:30:47 +04:00
res = sam . search ( expression = " sAMAccountName= %s " %
2011-10-21 19:49:29 +04:00
ldb . binary_encode ( cleanedaccount ) ,
scope = ldb . SCOPE_SUBTREE ,
attrs = [ " msDS-AllowedToDelegateTo " ] )
if len ( res ) == 0 :
raise CommandError ( " Unable to find account name ' %s ' " % accountname )
2024-02-12 06:13:13 +03:00
elif len ( res ) != 1 :
raise CommandError ( " Found multiple accounts. " )
2011-06-24 18:59:24 +04:00
msg = ldb . Message ( )
msg . dn = res [ 0 ] . dn
msg [ " msDS-AllowedToDelegateTo " ] = ldb . MessageElement ( [ principal ] ,
2018-07-30 09:16:12 +03:00
ldb . FLAG_MOD_DELETE ,
" msDS-AllowedToDelegateTo " )
2011-06-24 18:59:24 +04:00
try :
sam . modify ( msg )
2018-02-14 00:07:23 +03:00
except Exception as err :
2011-06-24 18:59:24 +04:00
raise CommandError ( err )
2011-09-02 21:10:05 +04:00
2022-02-21 04:58:30 +03:00
class cmd_delegation_add_principal ( Command ) :
""" Add a principal to msDS-AllowedToActOnBehalfOfOtherIdentity that may delegate to an account. """
synopsis = " % prog <accountname> <principal> [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
}
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
]
takes_args = [ " accountname " , " principal " ]
def run ( self , accountname , principal , H = None , credopts = None , sambaopts = None ,
versionopts = None ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
paths = provision . provision_paths_from_lp ( lp , lp . get ( " realm " ) )
if H is None :
path = paths . samdb
else :
path = H
sam = SamDB ( path , session_info = system_session ( ) ,
credentials = creds , lp = lp )
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
cleanedaccount , _ , _ = _get_user_realm_domain ( accountname , sam )
2022-02-21 04:58:30 +03:00
account_res = sam . search (
expression = " sAMAccountName= %s " %
ldb . binary_encode ( cleanedaccount ) ,
scope = ldb . SCOPE_SUBTREE ,
attrs = [ " msDS-AllowedToActOnBehalfOfOtherIdentity " ] )
if len ( account_res ) == 0 :
raise CommandError ( f " Unable to find account name ' { accountname } ' " )
2024-02-12 06:13:13 +03:00
elif len ( account_res ) != 1 :
raise CommandError ( " Found multiple accounts. " )
2022-02-21 04:58:30 +03:00
data = account_res [ 0 ] . get (
" msDS-AllowedToActOnBehalfOfOtherIdentity " , idx = 0 )
if data is None :
# Create the security descriptor if it is not present.
owner_sid = security . dom_sid ( security . SID_BUILTIN_ADMINISTRATORS )
security_desc = security . descriptor ( )
security_desc . revision = security . SD_REVISION
security_desc . type = ( security . SEC_DESC_DACL_PRESENT |
security . SEC_DESC_SELF_RELATIVE )
security_desc . owner_sid = owner_sid
dacl = None
else :
try :
security_desc = ndr_unpack ( security . descriptor , data )
except RuntimeError :
raise CommandError ( f " Security Descriptor of attribute "
f " msDS-AllowedToActOnBehalfOfOtherIdentity "
f " for account ' { accountname } ' could not be "
f " unmarshalled! " )
dacl = security_desc . dacl
if dacl is None :
# Create the DACL if it is not present.
dacl = security . acl ( )
dacl . revision = security . SECURITY_ACL_REVISION_ADS
dacl . num_aces = 0
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
cleanedprinc , _ , _ = _get_user_realm_domain ( principal , sam )
2022-02-21 04:58:30 +03:00
princ_res = sam . search ( expression = " sAMAccountName= %s " %
ldb . binary_encode ( cleanedprinc ) ,
scope = ldb . SCOPE_SUBTREE ,
attrs = [ " objectSid " ] )
if len ( princ_res ) == 0 :
raise CommandError ( f " Unable to find principal name ' { principal } ' " )
2024-02-12 06:13:13 +03:00
elif len ( princ_res ) != 1 :
raise CommandError ( " Found multiple accounts. " )
2022-02-21 04:58:30 +03:00
princ_sid = security . dom_sid (
sam . schema_format_value (
" objectSID " ,
princ_res [ 0 ] . get ( " objectSID " , idx = 0 ) ) . decode ( " utf-8 " ) )
aces = dacl . aces
# Check that there is no existing ACE for this principal.
if any ( ace . trustee == princ_sid for ace in aces ) :
raise CommandError (
f " ACE for principal ' { principal } ' already present in Security "
f " Descriptor of attribute "
f " msDS-AllowedToActOnBehalfOfOtherIdentity for account "
f " ' { accountname } ' . " )
# Create the new ACE.
ace = security . ace ( )
ace . type = security . SEC_ACE_TYPE_ACCESS_ALLOWED
ace . flags = 0
ace . access_mask = security . SEC_ADS_GENERIC_ALL
ace . trustee = princ_sid
aces . append ( ace )
dacl . aces = aces
dacl . num_aces + = 1
security_desc . dacl = dacl
new_data = ndr_pack ( security_desc )
# Set the new security descriptor. First, delete the original value to
# detect a race condition if someone else updates the attribute at the
# same time.
msg = ldb . Message ( )
msg . dn = account_res [ 0 ] . dn
if data is not None :
msg [ " 0 " ] = ldb . MessageElement (
data , ldb . FLAG_MOD_DELETE ,
" msDS-AllowedToActOnBehalfOfOtherIdentity " )
msg [ " 1 " ] = ldb . MessageElement (
new_data , ldb . FLAG_MOD_ADD ,
" msDS-AllowedToActOnBehalfOfOtherIdentity " )
try :
sam . modify ( msg )
except ldb . LdbError as err :
num , _ = err . args
if num == ldb . ERR_NO_SUCH_ATTRIBUTE :
raise CommandError (
f " Refused to update attribute "
f " msDS-AllowedToActOnBehalfOfOtherIdentity for account "
f " ' { accountname } ' : a conflicting attribute update "
f " occurred simultaneously. " )
else :
raise CommandError ( err )
class cmd_delegation_del_principal ( Command ) :
""" Delete a principal from msDS-AllowedToActOnBehalfOfOtherIdentity that may no longer delegate to an account. """
synopsis = " % prog <accountname> <principal> [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
}
takes_options = [
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " ) ,
]
takes_args = [ " accountname " , " principal " ]
def run ( self , accountname , principal , H = None , credopts = None , sambaopts = None ,
versionopts = None ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
paths = provision . provision_paths_from_lp ( lp , lp . get ( " realm " ) )
if H is None :
path = paths . samdb
else :
path = H
sam = SamDB ( path , session_info = system_session ( ) ,
credentials = creds , lp = lp )
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
cleanedaccount , _ , _ = _get_user_realm_domain ( accountname , sam )
2022-02-21 04:58:30 +03:00
account_res = sam . search (
expression = " sAMAccountName= %s " %
ldb . binary_encode ( cleanedaccount ) ,
scope = ldb . SCOPE_SUBTREE ,
attrs = [ " msDS-AllowedToActOnBehalfOfOtherIdentity " ] )
if len ( account_res ) == 0 :
raise CommandError ( " Unable to find account name ' %s ' " % accountname )
2024-02-12 06:13:13 +03:00
elif len ( account_res ) != 1 :
raise CommandError ( " Found multiple accounts. " )
2022-02-21 04:58:30 +03:00
data = account_res [ 0 ] . get (
" msDS-AllowedToActOnBehalfOfOtherIdentity " , idx = 0 )
if data is None :
raise CommandError ( f " Attribute "
f " msDS-AllowedToActOnBehalfOfOtherIdentity for "
f " account ' { accountname } ' not present! " )
try :
security_desc = ndr_unpack ( security . descriptor , data )
except RuntimeError :
raise CommandError ( f " Security Descriptor of attribute "
f " msDS-AllowedToActOnBehalfOfOtherIdentity for "
f " account ' { accountname } ' could not be "
f " unmarshalled! " )
dacl = security_desc . dacl
if dacl is None :
raise CommandError ( f " DACL not present on Security Descriptor of "
f " attribute "
f " msDS-AllowedToActOnBehalfOfOtherIdentity for "
f " account ' { accountname } ' ! " )
# TODO once I understand how, use the domain info to naildown
# to the correct domain
2022-02-24 01:05:57 +03:00
cleanedprinc , _ , _ = _get_user_realm_domain ( principal , sam )
2022-02-21 04:58:30 +03:00
princ_res = sam . search ( expression = " sAMAccountName= %s " %
ldb . binary_encode ( cleanedprinc ) ,
scope = ldb . SCOPE_SUBTREE ,
attrs = [ " objectSid " ] )
if len ( princ_res ) == 0 :
raise CommandError ( f " Unable to find principal name ' { principal } ' " )
2024-02-12 06:13:13 +03:00
elif len ( princ_res ) != 1 :
raise CommandError ( " Found multiple accounts. " )
2022-02-21 04:58:30 +03:00
princ_sid = security . dom_sid (
sam . schema_format_value (
" objectSID " ,
princ_res [ 0 ] . get ( " objectSID " , idx = 0 ) ) . decode ( " utf-8 " ) )
old_aces = dacl . aces
# Remove any ACEs relating to the specified principal.
aces = [ ace for ace in old_aces if ace . trustee != princ_sid ]
# Raise an error if we didn't find any.
if len ( aces ) == len ( old_aces ) :
raise CommandError ( f " Unable to find ACE for principal "
f " ' { principal } ' in Security Descriptor of "
f " attribute "
f " msDS-AllowedToActOnBehalfOfOtherIdentity for "
f " account ' { accountname } ' . " )
dacl . num_aces = len ( aces )
dacl . aces = aces
security_desc . dacl = dacl
new_data = ndr_pack ( security_desc )
# Set the new security descriptor. First, delete the original value to
# detect a race condition if someone else updates the attribute at the
# same time.
msg = ldb . Message ( )
msg . dn = account_res [ 0 ] . dn
msg [ " 0 " ] = ldb . MessageElement (
data , ldb . FLAG_MOD_DELETE ,
" msDS-AllowedToActOnBehalfOfOtherIdentity " )
msg [ " 1 " ] = ldb . MessageElement (
new_data , ldb . FLAG_MOD_ADD ,
" msDS-AllowedToActOnBehalfOfOtherIdentity " )
try :
sam . modify ( msg )
except ldb . LdbError as err :
num , _ = err . args
if num == ldb . ERR_NO_SUCH_ATTRIBUTE :
raise CommandError (
f " Refused to update attribute "
f " msDS-AllowedToActOnBehalfOfOtherIdentity for account "
f " ' { accountname } ' : a conflicting attribute update "
f " occurred simultaneously. " )
else :
raise CommandError ( err )
2011-06-24 18:59:24 +04:00
class cmd_delegation ( SuperCommand ) :
2012-10-09 13:53:21 +04:00
""" Delegation management. """
2011-06-24 18:59:24 +04:00
subcommands = { }
subcommands [ " show " ] = cmd_delegation_show ( )
subcommands [ " for-any-service " ] = cmd_delegation_for_any_service ( )
subcommands [ " for-any-protocol " ] = cmd_delegation_for_any_protocol ( )
subcommands [ " add-service " ] = cmd_delegation_add_service ( )
subcommands [ " del-service " ] = cmd_delegation_del_service ( )
2022-02-21 04:58:30 +03:00
subcommands [ " add-principal " ] = cmd_delegation_add_principal ( )
subcommands [ " del-principal " ] = cmd_delegation_del_principal ( )