2010-11-28 04:20:15 +03:00
# implement samba_tool gpo commands
#
# Copyright Andrew Tridgell 2010
2011-07-28 08:07:44 +04:00
# Copyright Amitay Isaacs 2011 <amitay@gmail.com>
2010-11-28 04:20:15 +03:00
#
# based on C implementation by Guenther Deschner and Wilco Baan Hofman
#
# 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/>.
#
2011-07-28 08:17:19 +04:00
import os
2010-11-28 04:20:15 +03:00
import samba . getopt as options
import ldb
from samba . auth import system_session
from samba . netcmd import (
Command ,
CommandError ,
Option ,
SuperCommand ,
)
from samba . samdb import SamDB
2011-12-07 06:10:10 +04:00
from samba import dsdb
from samba . dcerpc import security
2011-01-11 10:40:54 +03:00
from samba . ndr import ndr_unpack
import samba . security
import samba . auth
from samba . auth import AUTH_SESSION_INFO_DEFAULT_GROUPS , AUTH_SESSION_INFO_AUTHENTICATED , AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
2011-07-28 08:07:44 +04:00
from samba . netcmd . common import netcmd_finddc
2011-08-01 09:41:19 +04:00
from samba import policy
2011-07-28 08:17:19 +04:00
from samba import smb
2011-08-02 10:13:43 +04:00
import uuid
2011-12-07 06:10:10 +04:00
from samba . ntacls import dsacl2fsacl
2011-07-28 08:07:44 +04:00
2010-11-28 04:20:15 +03:00
def samdb_connect ( ctx ) :
''' make a ldap connection to the server '''
try :
ctx . samdb = SamDB ( url = ctx . url ,
session_info = system_session ( ) ,
credentials = ctx . creds , lp = ctx . lp )
2010-11-29 06:15:57 +03:00
except Exception , e :
raise CommandError ( " LDAP connection to %s failed " % ctx . url , e )
2010-11-28 04:20:15 +03:00
def attr_default ( msg , attrname , default ) :
''' get an attribute from a ldap msg with a default '''
if attrname in msg :
return msg [ attrname ] [ 0 ]
return default
2011-08-01 09:41:19 +04:00
def gpo_flags_string ( value ) :
''' return gpo flags string '''
flags = policy . get_gpo_flags ( value )
if not flags :
ret = ' NONE '
else :
ret = ' ' . join ( flags )
return ret
def gplink_options_string ( value ) :
''' return gplink options string '''
options = policy . get_gplink_options ( value )
if not options :
ret = ' NONE '
else :
ret = ' ' . join ( options )
return ret
2010-11-28 04:20:15 +03:00
2010-11-28 06:33:12 +03:00
def parse_gplink ( gplink ) :
''' parse a gPLink into an array of dn and options '''
ret = [ ]
a = gplink . split ( ' ] ' )
for g in a :
if not g :
continue
d = g . split ( ' ; ' )
if len ( d ) != 2 or not d [ 0 ] . startswith ( " [LDAP:// " ) :
raise RuntimeError ( " Badly formed gPLink ' %s ' " % g )
ret . append ( { ' dn ' : d [ 0 ] [ 8 : ] , ' options ' : int ( d [ 1 ] ) } )
return ret
2011-07-14 02:21:19 +04:00
def encode_gplink ( gplist ) :
''' Encode an array of dn and options into gPLink string '''
ret = ' '
for g in gplist :
ret + = " [LDAP:// %s ; %d ] " % ( g [ ' dn ' ] , g [ ' options ' ] )
return ret
2011-07-28 08:07:44 +04:00
def dc_url ( lp , creds , url = None , dc = None ) :
''' If URL is not specified, return URL for writable DC.
If dc is provided , use that to construct ldap URL '''
if url is None :
if dc is None :
try :
dc = netcmd_finddc ( lp , creds )
except Exception , e :
2011-12-14 05:18:57 +04:00
raise RuntimeError ( " Could not find a DC for domain " , e )
2011-07-28 08:07:44 +04:00
url = ' ldap:// ' + dc
return url
def get_gpo_dn ( samdb , gpo ) :
''' Construct the DN for gpo '''
dn = samdb . get_default_basedn ( )
2012-07-03 05:21:25 +04:00
dn . add_child ( ldb . Dn ( samdb , " CN=Policies,CN=System " ) )
2011-07-28 08:07:44 +04:00
dn . add_child ( ldb . Dn ( samdb , " CN= %s " % gpo ) )
return dn
def get_gpo_info ( samdb , gpo = None , displayname = None , dn = None ) :
''' Get GPO information using gpo, displayname or dn '''
policies_dn = samdb . get_default_basedn ( )
policies_dn . add_child ( ldb . Dn ( samdb , " CN=Policies,CN=System " ) )
base_dn = policies_dn
search_expr = " (objectClass=groupPolicyContainer) "
search_scope = ldb . SCOPE_ONELEVEL
if gpo is not None :
2011-07-28 11:14:28 +04:00
search_expr = " (&(objectClass=groupPolicyContainer)(name= %s )) " % ldb . binary_encode ( gpo )
2011-07-28 08:07:44 +04:00
if displayname is not None :
2011-07-28 11:14:28 +04:00
search_expr = " (&(objectClass=groupPolicyContainer)(displayname= %s )) " % ldb . binary_encode ( displayname )
2011-07-28 08:07:44 +04:00
if dn is not None :
base_dn = dn
search_scope = ldb . SCOPE_BASE
try :
msg = samdb . search ( base = base_dn , scope = search_scope ,
expression = search_expr ,
attrs = [ ' nTSecurityDescriptor ' ,
' versionNumber ' ,
' flags ' ,
' name ' ,
' displayName ' ,
' gPCFileSysPath ' ] )
except Exception , e :
if gpo is not None :
mesg = " Cannot get information for GPO %s " % gpo
else :
mesg = " Cannot get information for GPOs "
raise CommandError ( mesg , e )
return msg
2012-07-03 08:13:01 +04:00
def get_gpo_containers ( samdb , gpo ) :
''' lists dn of containers for a GPO '''
search_expr = " (&(objectClass=*)(gPLink=* %s *)) " % gpo
try :
msg = samdb . search ( expression = search_expr , attrs = [ ' gPLink ' ] )
except Exception , e :
raise CommandError ( " Could not find container(s) with GPO %s " % gpo , e )
return msg
def del_gpo_link ( samdb , container_dn , gpo ) :
''' delete GPO link for the container '''
# Check if valid Container DN and get existing GPlinks
try :
msg = samdb . search ( base = container_dn , scope = ldb . SCOPE_BASE ,
expression = " (objectClass=*) " ,
attrs = [ ' gPLink ' ] ) [ 0 ]
except Exception , e :
raise CommandError ( " Container %s does not exist " % container_dn , e )
found = False
gpo_dn = str ( get_gpo_dn ( samdb , gpo ) )
if ' gPLink ' in msg :
gplist = parse_gplink ( msg [ ' gPLink ' ] [ 0 ] )
for g in gplist :
if g [ ' dn ' ] . lower ( ) == gpo_dn . lower ( ) :
gplist . remove ( g )
found = True
break
else :
raise CommandError ( " No GPO(s) linked to this container " )
if not found :
raise CommandError ( " GPO ' %s ' not linked to this container " % gpo )
m = ldb . Message ( )
m . dn = container_dn
if gplist :
gplink_str = encode_gplink ( gplist )
m [ ' r0 ' ] = ldb . MessageElement ( gplink_str , ldb . FLAG_MOD_REPLACE , ' gPLink ' )
else :
m [ ' d0 ' ] = ldb . MessageElement ( msg [ ' gPLink ' ] [ 0 ] , ldb . FLAG_MOD_DELETE , ' gPLink ' )
try :
samdb . modify ( m )
except Exception , e :
raise CommandError ( " Error removing GPO from container " , e )
2011-07-28 08:17:19 +04:00
def parse_unc ( unc ) :
''' Parse UNC string into a hostname, a service, and a filepath '''
if unc . startswith ( ' \\ \\ ' ) and unc . startswith ( ' // ' ) :
2011-10-08 16:13:04 +04:00
raise ValueError ( " UNC doesn ' t start with \\ \\ or // " )
2011-07-28 08:17:19 +04:00
tmp = unc [ 2 : ] . split ( ' / ' , 2 )
if len ( tmp ) == 3 :
return tmp
tmp = unc [ 2 : ] . split ( ' \\ ' , 2 )
if len ( tmp ) == 3 :
2011-10-08 16:13:04 +04:00
return tmp
raise ValueError ( " Invalid UNC string: %s " % unc )
2011-07-28 08:17:19 +04:00
2011-08-01 09:47:10 +04:00
def copy_directory_remote_to_local ( conn , remotedir , localdir ) :
2011-07-28 08:17:19 +04:00
if not os . path . isdir ( localdir ) :
os . mkdir ( localdir )
r_dirs = [ remotedir ]
l_dirs = [ localdir ]
while r_dirs :
r_dir = r_dirs . pop ( )
l_dir = l_dirs . pop ( )
dirlist = conn . list ( r_dir )
for e in dirlist :
r_name = r_dir + ' \\ ' + e [ ' name ' ]
2011-08-01 09:47:10 +04:00
l_name = os . path . join ( l_dir , e [ ' name ' ] )
2011-07-28 08:17:19 +04:00
if e [ ' attrib ' ] & smb . FILE_ATTRIBUTE_DIRECTORY :
r_dirs . append ( r_name )
l_dirs . append ( l_name )
os . mkdir ( l_name )
2011-08-01 09:47:10 +04:00
else :
2011-07-28 08:17:19 +04:00
data = conn . loadfile ( r_name )
file ( l_name , ' w ' ) . write ( data )
2011-08-02 10:13:01 +04:00
def copy_directory_local_to_remote ( conn , localdir , remotedir ) :
if not conn . chkpath ( remotedir ) :
conn . mkdir ( remotedir )
l_dirs = [ localdir ]
r_dirs = [ remotedir ]
while l_dirs :
l_dir = l_dirs . pop ( )
r_dir = r_dirs . pop ( )
dirlist = os . listdir ( l_dir )
for e in dirlist :
l_name = os . path . join ( l_dir , e )
r_name = r_dir + ' \\ ' + e
if os . path . isdir ( l_name ) :
l_dirs . append ( l_name )
r_dirs . append ( r_name )
conn . mkdir ( r_name )
else :
data = file ( l_name , ' r ' ) . read ( )
conn . savefile ( r_name , data )
def create_directory_hier ( conn , remotedir ) :
elems = remotedir . replace ( ' / ' , ' \\ ' ) . split ( ' \\ ' )
path = " "
for e in elems :
path = path + ' \\ ' + e
if not conn . chkpath ( path ) :
conn . mkdir ( path )
2010-11-28 04:20:15 +03:00
class cmd_listall ( Command ) :
""" list all GPOs """
2011-10-14 01:27:22 +04:00
synopsis = " % prog [options] "
2010-11-28 04:20:15 +03:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2010-11-28 04:20:15 +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-11-28 04:20:15 +03:00
]
2011-07-14 02:21:19 +04:00
def run ( self , H = None , sambaopts = None , credopts = None , versionopts = None ) :
2010-11-28 04:20:15 +03:00
self . lp = sambaopts . get_loadparm ( )
2010-12-08 00:20:54 +03:00
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2010-11-28 04:20:15 +03:00
2011-07-28 08:07:44 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2010-11-28 04:20:15 +03:00
2011-07-28 08:07:44 +04:00
samdb_connect ( self )
2010-11-28 04:20:15 +03:00
2011-07-28 08:07:44 +04:00
msg = get_gpo_info ( self . samdb , None )
2010-11-28 04:20:15 +03:00
for m in msg :
2011-10-13 02:36:44 +04:00
self . outf . write ( " GPO : %s \n " % m [ ' name ' ] [ 0 ] )
self . outf . write ( " display name : %s \n " % m [ ' displayName ' ] [ 0 ] )
self . outf . write ( " path : %s \n " % m [ ' gPCFileSysPath ' ] [ 0 ] )
self . outf . write ( " dn : %s \n " % m . dn )
self . outf . write ( " version : %s \n " % attr_default ( m , ' versionNumber ' , ' 0 ' ) )
self . outf . write ( " flags : %s \n " % gpo_flags_string ( int ( attr_default ( m , ' flags ' , 0 ) ) ) )
self . outf . write ( " \n " )
2010-11-28 04:20:15 +03:00
2010-11-28 06:33:12 +03:00
class cmd_list ( Command ) :
2011-07-14 02:21:19 +04:00
""" list GPOs for an account """
2010-11-28 06:33:12 +03:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog <username> [options] "
2010-11-28 06:33:12 +03:00
2011-10-14 01:27:22 +04:00
takes_args = [ ' username ' ]
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2010-11-28 06:33:12 +03:00
takes_options = [
2011-10-14 01:27:22 +04:00
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " ,
type = str , metavar = " URL " , dest = " H " )
2010-11-28 06:33:12 +03:00
]
2011-07-14 02:21:19 +04:00
def run ( self , username , H = None , sambaopts = None , credopts = None , versionopts = None ) :
2010-11-28 06:33:12 +03:00
self . lp = sambaopts . get_loadparm ( )
2010-12-08 00:20:54 +03:00
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2010-11-28 06:33:12 +03:00
2011-07-28 08:07:44 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2010-11-28 06:33:12 +03:00
samdb_connect ( self )
try :
2011-07-14 02:21:19 +04:00
msg = self . samdb . search ( expression = ' (&(|(samAccountName= %s )(samAccountName= %s $))(objectClass=User)) ' %
2011-07-28 11:14:28 +04:00
( ldb . binary_encode ( username ) , ldb . binary_encode ( username ) ) )
2011-07-14 02:21:19 +04:00
user_dn = msg [ 0 ] . dn
2010-11-29 06:15:57 +03:00
except Exception , e :
2011-07-14 02:21:19 +04:00
raise CommandError ( " Failed to find account %s " % username , e )
2010-11-28 06:33:12 +03:00
# check if its a computer account
try :
msg = self . samdb . search ( base = user_dn , scope = ldb . SCOPE_BASE , attrs = [ ' objectClass ' ] ) [ 0 ]
is_computer = ' computer ' in msg [ ' objectClass ' ]
2010-11-29 06:15:57 +03:00
except Exception , e :
raise CommandError ( " Failed to find objectClass for user %s " % username , e )
2010-11-28 06:33:12 +03:00
2011-01-11 10:40:54 +03:00
session_info_flags = ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
AUTH_SESSION_INFO_AUTHENTICATED )
# When connecting to a remote server, don't look up the local privilege DB
if self . url is not None and self . url . startswith ( ' ldap ' ) :
session_info_flags | = AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
session = samba . auth . user_session ( self . samdb , lp_ctx = self . lp , dn = user_dn ,
session_info_flags = session_info_flags )
token = session . security_token
2010-11-28 06:33:12 +03:00
gpos = [ ]
inherit = True
dn = ldb . Dn ( self . samdb , str ( user_dn ) ) . parent ( )
while True :
2011-01-13 07:09:03 +03:00
msg = self . samdb . search ( base = dn , scope = ldb . SCOPE_BASE , attrs = [ ' gPLink ' , ' gPOptions ' ] ) [ 0 ]
2010-11-28 06:33:12 +03:00
if ' gPLink ' in msg :
glist = parse_gplink ( msg [ ' gPLink ' ] [ 0 ] )
for g in glist :
if not inherit and not ( g [ ' options ' ] & dsdb . GPLINK_OPT_ENFORCE ) :
continue
if g [ ' options ' ] & dsdb . GPLINK_OPT_DISABLE :
continue
2011-01-13 07:09:03 +03:00
try :
gmsg = self . samdb . search ( base = g [ ' dn ' ] , scope = ldb . SCOPE_BASE ,
2011-07-28 08:07:44 +04:00
attrs = [ ' name ' , ' displayName ' , ' flags ' ,
' ntSecurityDescriptor ' ] )
2011-01-13 07:09:03 +03:00
except Exception :
2011-10-13 02:36:44 +04:00
self . outf . write ( " Failed to fetch gpo object %s \n " %
g [ ' dn ' ] )
2011-01-13 07:09:03 +03:00
continue
secdesc_ndr = gmsg [ 0 ] [ ' ntSecurityDescriptor ' ] [ 0 ]
2011-12-07 06:10:10 +04:00
secdesc = ndr_unpack ( security . descriptor , secdesc_ndr )
2011-01-11 10:40:54 +03:00
try :
2011-01-13 07:09:03 +03:00
samba . security . access_check ( secdesc , token ,
2011-12-07 06:10:10 +04:00
security . SEC_STD_READ_CONTROL |
security . SEC_ADS_LIST |
security . SEC_ADS_READ_PROP )
2011-01-11 10:40:54 +03:00
except RuntimeError :
2011-10-13 02:36:44 +04:00
self . outf . write ( " Failed access check on %s \n " % msg . dn )
2011-01-11 10:40:54 +03:00
continue
2010-11-28 06:33:12 +03:00
# check the flags on the GPO
2011-01-13 07:09:03 +03:00
flags = int ( attr_default ( gmsg [ 0 ] , ' flags ' , 0 ) )
2010-11-28 06:33:12 +03:00
if is_computer and ( flags & dsdb . GPO_FLAG_MACHINE_DISABLE ) :
continue
if not is_computer and ( flags & dsdb . GPO_FLAG_USER_DISABLE ) :
continue
2011-07-28 08:07:44 +04:00
gpos . append ( ( gmsg [ 0 ] [ ' displayName ' ] [ 0 ] , gmsg [ 0 ] [ ' name ' ] [ 0 ] ) )
2010-11-28 06:33:12 +03:00
# check if this blocks inheritance
gpoptions = int ( attr_default ( msg , ' gPOptions ' , 0 ) )
if gpoptions & dsdb . GPO_BLOCK_INHERITANCE :
inherit = False
if dn == self . samdb . get_default_basedn ( ) :
break
dn = dn . parent ( )
2011-07-14 02:21:19 +04:00
if is_computer :
msg_str = ' computer '
else :
msg_str = ' user '
2011-10-13 02:36:44 +04:00
self . outf . write ( " GPOs for %s %s \n " % ( msg_str , username ) )
2010-11-28 06:33:12 +03:00
for g in gpos :
2011-10-13 02:36:44 +04:00
self . outf . write ( " %s %s \n " % ( g [ 0 ] , g [ 1 ] ) )
2011-07-14 02:21:19 +04:00
class cmd_show ( Command ) :
""" Show information for a GPO """
2011-10-14 01:27:22 +04:00
synopsis = " % prog <gpo> [options] "
2011-07-14 02:21:19 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-10-14 01:27:22 +04:00
takes_args = [ ' gpo ' ]
2011-07-14 02:21:19 +04:00
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str )
]
2011-07-28 08:07:44 +04:00
def run ( self , gpo , H = None , sambaopts = None , credopts = None , versionopts = None ) :
2011-07-14 02:21:19 +04:00
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2011-07-28 08:07:44 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2011-07-14 02:21:19 +04:00
samdb_connect ( self )
try :
2011-07-28 08:07:44 +04:00
msg = get_gpo_info ( self . samdb , gpo ) [ 0 ]
2011-07-14 02:21:19 +04:00
except Exception , e :
2011-07-28 08:07:44 +04:00
raise CommandError ( " GPO %s does not exist " % gpo , e )
2011-07-14 02:21:19 +04:00
secdesc_ndr = msg [ ' ntSecurityDescriptor ' ] [ 0 ]
2011-12-07 06:10:10 +04:00
secdesc = ndr_unpack ( security . descriptor , secdesc_ndr )
2011-07-14 02:21:19 +04:00
2011-10-13 02:36:44 +04:00
self . outf . write ( " GPO : %s \n " % msg [ ' name ' ] [ 0 ] )
self . outf . write ( " display name : %s \n " % msg [ ' displayName ' ] [ 0 ] )
self . outf . write ( " path : %s \n " % msg [ ' gPCFileSysPath ' ] [ 0 ] )
self . outf . write ( " dn : %s \n " % msg . dn )
self . outf . write ( " version : %s \n " % attr_default ( msg , ' versionNumber ' , ' 0 ' ) )
self . outf . write ( " flags : %s \n " % gpo_flags_string ( int ( attr_default ( msg , ' flags ' , 0 ) ) ) )
self . outf . write ( " ACL : %s \n " % secdesc . as_sddl ( ) )
self . outf . write ( " \n " )
2011-07-14 02:21:19 +04:00
class cmd_getlink ( Command ) :
""" List GPO Links for a container """
2011-10-14 01:27:22 +04:00
synopsis = " % prog <container_dn> [options] "
2011-07-14 02:21:19 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-10-14 01:27:22 +04:00
takes_args = [ ' container_dn ' ]
2011-07-14 02:21:19 +04:00
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str )
]
def run ( self , container_dn , H = None , sambaopts = None , credopts = None ,
versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2011-07-28 08:07:44 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2011-07-14 02:21:19 +04:00
samdb_connect ( self )
try :
msg = self . samdb . search ( base = container_dn , scope = ldb . SCOPE_BASE ,
expression = " (objectClass=*) " ,
2012-07-03 05:22:55 +04:00
attrs = [ ' gPLink ' ] ) [ 0 ]
2011-07-14 02:21:19 +04:00
except Exception , e :
raise CommandError ( " Could not find Container DN %s ( %s ) " % container_dn , e )
2012-07-03 05:22:55 +04:00
if msg [ ' gPLink ' ] :
2011-10-13 02:36:44 +04:00
self . outf . write ( " GPO(s) linked to DN %s \n " % container_dn )
2011-07-14 02:21:19 +04:00
gplist = parse_gplink ( msg [ ' gPLink ' ] [ 0 ] )
for g in gplist :
2011-07-28 08:07:44 +04:00
msg = get_gpo_info ( self . samdb , dn = g [ ' dn ' ] )
2011-10-13 02:36:44 +04:00
self . outf . write ( " GPO : %s \n " % msg [ 0 ] [ ' name ' ] [ 0 ] )
self . outf . write ( " Name : %s \n " % msg [ 0 ] [ ' displayName ' ] [ 0 ] )
self . outf . write ( " Options : %s \n " % gplink_options_string ( g [ ' options ' ] ) )
self . outf . write ( " \n " )
2011-07-14 02:21:19 +04:00
else :
2011-10-13 02:36:44 +04:00
self . outf . write ( " No GPO(s) linked to DN= %s \n " % container_dn )
2011-07-14 02:21:19 +04:00
class cmd_setlink ( Command ) :
""" Add or Update a GPO link to a container """
2011-10-14 01:27:22 +04:00
synopsis = " % prog <container_dn> <gpo> [options] "
2011-07-14 02:21:19 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-10-14 01:27:22 +04:00
takes_args = [ ' container_dn ' , ' gpo ' ]
2011-07-14 02:21:19 +04:00
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str ) ,
Option ( " --disable " , dest = " disabled " , default = False , action = ' store_true ' ,
help = " Disable policy " ) ,
Option ( " --enforce " , dest = " enforced " , default = False , action = ' store_true ' ,
help = " Enforce policy " )
]
2011-07-28 08:07:44 +04:00
def run ( self , container_dn , gpo , H = None , disabled = False , enforced = False ,
2011-07-14 02:21:19 +04:00
sambaopts = None , credopts = None , versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2011-07-28 08:07:44 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2011-07-14 02:21:19 +04:00
samdb_connect ( self )
gplink_options = 0
if disabled :
gplink_options | = dsdb . GPLINK_OPT_DISABLE
if enforced :
gplink_options | = dsdb . GPLINK_OPT_ENFORCE
# Check if valid GPO DN
try :
2011-07-28 08:07:44 +04:00
msg = get_gpo_info ( self . samdb , gpo = gpo ) [ 0 ]
2011-07-14 02:21:19 +04:00
except Exception , e :
2012-07-03 05:26:41 +04:00
raise CommandError ( " GPO %s does not exist " % gpo , e )
gpo_dn = str ( get_gpo_dn ( self . samdb , gpo ) )
2011-07-14 02:21:19 +04:00
# Check if valid Container DN
try :
msg = self . samdb . search ( base = container_dn , scope = ldb . SCOPE_BASE ,
expression = " (objectClass=*) " ,
2012-07-03 05:22:55 +04:00
attrs = [ ' gPLink ' ] ) [ 0 ]
2011-07-14 02:21:19 +04:00
except Exception , e :
2011-07-28 08:07:44 +04:00
raise CommandError ( " Could not find container DN %s " % container_dn , e )
2011-07-14 02:21:19 +04:00
# Update existing GPlinks or Add new one
existing_gplink = False
if ' gPLink ' in msg :
gplist = parse_gplink ( msg [ ' gPLink ' ] [ 0 ] )
existing_gplink = True
found = False
for g in gplist :
if g [ ' dn ' ] . lower ( ) == gpo_dn . lower ( ) :
g [ ' options ' ] = gplink_options
found = True
break
if not found :
gplist . insert ( 0 , { ' dn ' : gpo_dn , ' options ' : gplink_options } )
else :
gplist = [ ]
gplist . append ( { ' dn ' : gpo_dn , ' options ' : gplink_options } )
gplink_str = encode_gplink ( gplist )
m = ldb . Message ( )
m . dn = ldb . Dn ( self . samdb , container_dn )
if existing_gplink :
m [ ' new_value ' ] = ldb . MessageElement ( gplink_str , ldb . FLAG_MOD_REPLACE , ' gPLink ' )
else :
m [ ' new_value ' ] = ldb . MessageElement ( gplink_str , ldb . FLAG_MOD_ADD , ' gPLink ' )
try :
self . samdb . modify ( m )
except Exception , e :
2011-07-28 08:07:44 +04:00
raise CommandError ( " Error adding GPO Link " , e )
2011-07-14 02:21:19 +04:00
2011-10-13 02:36:44 +04:00
self . outf . write ( " Added/Updated GPO link \n " )
2011-07-14 02:21:19 +04:00
cmd_getlink ( ) . run ( container_dn , H , sambaopts , credopts , versionopts )
class cmd_dellink ( Command ) :
""" Delete GPO link from a container """
2011-10-14 01:27:22 +04:00
synopsis = " % prog <container_dn> <gpo> [options] "
2011-07-14 02:21:19 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2012-07-03 08:16:41 +04:00
takes_args = [ ' container ' , ' gpo ' ]
2011-07-14 02:21:19 +04:00
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str ) ,
]
2012-07-03 08:16:41 +04:00
def run ( self , container , gpo , H = None , sambaopts = None , credopts = None ,
2011-07-14 02:21:19 +04:00
versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2011-07-28 08:07:44 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2011-07-14 02:21:19 +04:00
samdb_connect ( self )
2011-07-28 08:07:44 +04:00
# Check if valid GPO
2011-07-14 02:21:19 +04:00
try :
2012-07-03 08:16:41 +04:00
get_gpo_info ( self . samdb , gpo = gpo ) [ 0 ]
2011-07-14 02:21:19 +04:00
except Exception , e :
2012-07-03 08:16:41 +04:00
raise CommandError ( " GPO %s does not exist " % gpo , e )
2011-07-14 02:21:19 +04:00
2012-07-03 08:16:41 +04:00
container_dn = ldb . Dn ( self . samdb , container )
del_gpo_link ( self . samdb , container_dn , gpo )
2011-10-13 02:36:44 +04:00
self . outf . write ( " Deleted GPO link. \n " )
2011-07-14 02:21:19 +04:00
cmd_getlink ( ) . run ( container_dn , H , sambaopts , credopts , versionopts )
class cmd_getinheritance ( Command ) :
""" Get inheritance flag for a container """
2011-10-14 01:27:22 +04:00
synopsis = " % prog <container_dn> [options] "
2011-07-14 02:21:19 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-10-14 01:27:22 +04:00
takes_args = [ ' container_dn ' ]
2011-07-14 02:21:19 +04:00
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str )
]
def run ( self , container_dn , H = None , sambaopts = None , credopts = None ,
versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2012-07-03 08:17:48 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2011-07-14 02:21:19 +04:00
samdb_connect ( self )
try :
msg = self . samdb . search ( base = container_dn , scope = ldb . SCOPE_BASE ,
expression = " (objectClass=*) " ,
attrs = [ ' gPOptions ' ] ) [ 0 ]
except Exception , e :
2011-07-28 08:07:44 +04:00
raise CommandError ( " Could not find Container DN %s " % container_dn , e )
2011-07-14 02:21:19 +04:00
inheritance = 0
if ' gPOptions ' in msg :
2011-10-08 16:13:04 +04:00
inheritance = int ( msg [ ' gPOptions ' ] [ 0 ] )
2011-07-14 02:21:19 +04:00
if inheritance == dsdb . GPO_BLOCK_INHERITANCE :
2011-10-13 02:36:44 +04:00
self . outf . write ( " Container has GPO_BLOCK_INHERITANCE \n " )
2011-07-14 02:21:19 +04:00
else :
2011-10-13 02:36:44 +04:00
self . outf . write ( " Container has GPO_INHERIT \n " )
2011-07-14 02:21:19 +04:00
class cmd_setinheritance ( Command ) :
""" Set inheritance flag on a container """
2011-10-14 01:27:22 +04:00
synopsis = " % prog <container_dn> <block|inherit> [options] "
2011-07-14 02:21:19 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
takes_args = [ ' container_dn ' , ' inherit_state ' ]
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str )
]
def run ( self , container_dn , inherit_state , H = None , sambaopts = None , credopts = None ,
versionopts = None ) :
if inherit_state . lower ( ) == ' block ' :
inheritance = dsdb . GPO_BLOCK_INHERITANCE
elif inherit_state . lower ( ) == ' inherit ' :
inheritance = dsdb . GPO_INHERIT
else :
raise CommandError ( " Unknown inheritance state ( %s ) " % inherit_state )
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2012-07-03 08:17:48 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2011-07-14 02:21:19 +04:00
2012-07-03 08:17:48 +04:00
samdb_connect ( self )
2011-07-14 02:21:19 +04:00
try :
msg = self . samdb . search ( base = container_dn , scope = ldb . SCOPE_BASE ,
expression = " (objectClass=*) " ,
attrs = [ ' gPOptions ' ] ) [ 0 ]
except Exception , e :
2011-07-28 08:07:44 +04:00
raise CommandError ( " Could not find Container DN %s " % container_dn , e )
2011-07-14 02:21:19 +04:00
m = ldb . Message ( )
m . dn = ldb . Dn ( self . samdb , container_dn )
if ' gPOptions ' in msg :
m [ ' new_value ' ] = ldb . MessageElement ( str ( inheritance ) , ldb . FLAG_MOD_REPLACE , ' gPOptions ' )
else :
2011-10-08 16:13:04 +04:00
m [ ' new_value ' ] = ldb . MessageElement ( str ( inheritance ) , ldb . FLAG_MOD_ADD , ' gPOptions ' )
2011-07-14 02:21:19 +04:00
try :
self . samdb . modify ( m )
except Exception , e :
2011-07-28 08:07:44 +04:00
raise CommandError ( " Error setting inheritance state %s " % inherit_state , e )
2011-07-14 02:21:19 +04:00
class cmd_fetch ( Command ) :
""" Download a GPO """
2011-10-14 01:27:22 +04:00
synopsis = " % prog <gpo> [options] "
2011-07-28 08:17:19 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-10-14 01:27:22 +04:00
takes_args = [ ' gpo ' ]
2011-07-28 08:17:19 +04:00
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str ) ,
Option ( " --tmpdir " , help = " Temporary directory for copying policy files " , type = str )
]
def run ( self , gpo , H = None , tmpdir = None , sambaopts = None , credopts = None , versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2012-07-03 08:17:48 +04:00
# We need to know writable DC to setup SMB connection
if H and H . startswith ( ' ldap:// ' ) :
dc_hostname = H [ 7 : ]
self . url = H
else :
dc_hostname = netcmd_finddc ( self . lp , self . creds )
self . url = dc_url ( self . lp , self . creds , dc = dc_hostname )
2011-07-28 08:17:19 +04:00
samdb_connect ( self )
try :
msg = get_gpo_info ( self . samdb , gpo ) [ 0 ]
except Exception , e :
raise CommandError ( " GPO %s does not exist " % gpo )
2011-08-01 09:47:10 +04:00
# verify UNC path
2011-07-28 08:17:19 +04:00
unc = msg [ ' gPCFileSysPath ' ] [ 0 ]
try :
[ dom_name , service , sharepath ] = parse_unc ( unc )
2011-10-08 16:13:04 +04:00
except ValueError :
2011-07-28 08:17:19 +04:00
raise CommandError ( " Invalid GPO path ( %s ) " % unc )
2011-08-01 09:47:10 +04:00
# SMB connect to DC
2011-07-28 08:17:19 +04:00
try :
conn = smb . SMB ( dc_hostname , service , lp = self . lp , creds = self . creds )
except Exception , e :
raise CommandError ( " Error connecting to ' %s ' using SMB " % dc_hostname , e )
2011-08-01 09:47:10 +04:00
# Copy GPT
2011-07-28 08:17:19 +04:00
if tmpdir is None :
tmpdir = " /tmp "
2011-08-01 09:47:10 +04:00
if not os . path . isdir ( tmpdir ) :
raise CommandError ( " Temoprary directory ' %s ' does not exist " % tmpdir )
localdir = os . path . join ( tmpdir , " policy " )
if not os . path . isdir ( localdir ) :
os . mkdir ( localdir )
gpodir = os . path . join ( localdir , gpo )
if os . path . isdir ( gpodir ) :
raise CommandError ( " GPO directory ' %s ' already exists, refusing to overwrite " % gpodir )
2011-07-28 08:17:19 +04:00
try :
2011-08-01 09:47:10 +04:00
os . mkdir ( gpodir )
copy_directory_remote_to_local ( conn , sharepath , gpodir )
2011-07-28 08:17:19 +04:00
except Exception , e :
2011-10-13 02:36:44 +04:00
# FIXME: Catch more specific exception
2011-08-01 09:47:10 +04:00
raise CommandError ( " Error copying GPO from DC " , e )
2011-10-13 02:36:44 +04:00
self . outf . write ( ' GPO copied to %s \n ' % gpodir )
2011-07-28 08:17:19 +04:00
2011-07-14 02:21:19 +04:00
class cmd_create ( Command ) :
2011-08-02 10:13:43 +04:00
""" Create an empty GPO """
2011-10-14 01:27:22 +04:00
synopsis = " % prog <displayname> [options] "
2011-08-02 10:13:43 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-10-14 01:27:22 +04:00
takes_args = [ ' displayname ' ]
2011-08-02 10:13:43 +04:00
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str ) ,
Option ( " --tmpdir " , help = " Temporary directory for copying policy files " , type = str )
]
def run ( self , displayname , H = None , tmpdir = None , sambaopts = None , credopts = None ,
versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2012-07-03 08:17:48 +04:00
# We need to know writable DC to setup SMB connection
if H and H . startswith ( ' ldap:// ' ) :
dc_hostname = H [ 7 : ]
self . url = H
else :
dc_hostname = netcmd_finddc ( self . lp , self . creds )
self . url = dc_url ( self . lp , self . creds , dc = dc_hostname )
2011-08-02 10:13:43 +04:00
samdb_connect ( self )
msg = get_gpo_info ( self . samdb , displayname = displayname )
if msg . count > 0 :
raise CommandError ( " A GPO already existing with name ' %s ' " % displayname )
# Create new GUID
guid = str ( uuid . uuid4 ( ) )
gpo = " { %s } " % guid . upper ( )
realm = self . lp . get ( ' realm ' )
unc_path = " \\ \\ %s \\ sysvol \\ %s \\ Policies \\ %s " % ( realm , realm , gpo )
# Create GPT
if tmpdir is None :
tmpdir = " /tmp "
if not os . path . isdir ( tmpdir ) :
raise CommandError ( " Temporary directory ' %s ' does not exist " % tmpdir )
localdir = os . path . join ( tmpdir , " policy " )
if not os . path . isdir ( localdir ) :
os . mkdir ( localdir )
gpodir = os . path . join ( localdir , gpo )
if os . path . isdir ( gpodir ) :
raise CommandError ( " GPO directory ' %s ' already exists, refusing to overwrite " % gpodir )
try :
os . mkdir ( gpodir )
os . mkdir ( os . path . join ( gpodir , " Machine " ) )
os . mkdir ( os . path . join ( gpodir , " User " ) )
gpt_contents = " [General] \r \n Version=0 \r \n "
file ( os . path . join ( gpodir , " GPT.INI " ) , " w " ) . write ( gpt_contents )
except Exception , e :
raise CommandError ( " Error Creating GPO files " , e )
2011-12-14 05:18:57 +04:00
# Connect to DC over SMB
[ dom_name , service , sharepath ] = parse_unc ( unc_path )
2011-08-02 10:13:43 +04:00
try :
2011-12-14 05:18:57 +04:00
conn = smb . SMB ( dc_hostname , service , lp = self . lp , creds = self . creds )
2011-08-02 10:13:43 +04:00
except Exception , e :
2011-12-14 05:18:57 +04:00
raise CommandError ( " Error connecting to ' %s ' using SMB " % dc_hostname , e )
2011-08-02 10:13:43 +04:00
2011-12-14 05:18:57 +04:00
self . samdb . transaction_start ( )
2011-08-02 10:13:43 +04:00
try :
2011-12-14 05:18:57 +04:00
# Add cn=<guid>
2012-07-03 08:16:41 +04:00
gpo_dn = get_gpo_dn ( self . samdb , gpo )
2011-12-14 05:18:57 +04:00
m = ldb . Message ( )
2012-07-03 08:16:41 +04:00
m . dn = gpo_dn
2011-12-14 05:18:57 +04:00
m [ ' a01 ' ] = ldb . MessageElement ( " groupPolicyContainer " , ldb . FLAG_MOD_ADD , " objectClass " )
m [ ' a02 ' ] = ldb . MessageElement ( displayname , ldb . FLAG_MOD_ADD , " displayName " )
m [ ' a03 ' ] = ldb . MessageElement ( unc_path , ldb . FLAG_MOD_ADD , " gPCFileSysPath " )
m [ ' a04 ' ] = ldb . MessageElement ( " 0 " , ldb . FLAG_MOD_ADD , " flags " )
m [ ' a05 ' ] = ldb . MessageElement ( " 0 " , ldb . FLAG_MOD_ADD , " versionNumber " )
m [ ' a06 ' ] = ldb . MessageElement ( " TRUE " , ldb . FLAG_MOD_ADD , " showInAdvancedViewOnly " )
m [ ' a07 ' ] = ldb . MessageElement ( " 2 " , ldb . FLAG_MOD_ADD , " gpcFunctionalityVersion " )
2011-08-02 10:13:43 +04:00
self . samdb . add ( m )
2011-12-14 05:18:57 +04:00
# Add cn=User,cn=<guid>
m = ldb . Message ( )
m . dn = ldb . Dn ( self . samdb , " CN=User, %s " % str ( gpo_dn ) )
m [ ' a01 ' ] = ldb . MessageElement ( " container " , ldb . FLAG_MOD_ADD , " objectClass " )
m [ ' a02 ' ] = ldb . MessageElement ( " TRUE " , ldb . FLAG_MOD_ADD , " showInAdvancedViewOnly " )
2011-08-02 10:13:43 +04:00
self . samdb . add ( m )
2011-12-14 05:18:57 +04:00
# Add cn=Machine,cn=<guid>
m = ldb . Message ( )
m . dn = ldb . Dn ( self . samdb , " CN=Machine, %s " % str ( gpo_dn ) )
m [ ' a01 ' ] = ldb . MessageElement ( " container " , ldb . FLAG_MOD_ADD , " objectClass " )
m [ ' a02 ' ] = ldb . MessageElement ( " TRUE " , ldb . FLAG_MOD_ADD , " showInAdvancedViewOnly " )
self . samdb . add ( m )
2011-08-02 10:13:43 +04:00
2011-12-14 05:18:57 +04:00
# Copy GPO files over SMB
2011-08-02 10:13:43 +04:00
create_directory_hier ( conn , sharepath )
copy_directory_local_to_remote ( conn , gpodir , sharepath )
2011-12-14 05:18:57 +04:00
# Get new security descriptor
msg = get_gpo_info ( self . samdb , gpo = gpo ) [ 0 ]
ds_sd_ndr = msg [ ' ntSecurityDescriptor ' ] [ 0 ]
ds_sd = ndr_unpack ( security . descriptor , ds_sd_ndr ) . as_sddl ( )
2011-08-02 10:13:43 +04:00
2011-12-14 05:18:57 +04:00
# Create a file system security descriptor
2012-06-19 10:49:33 +04:00
domain_sid = self . samdb . get_domain_sid ( )
sddl = dsacl2fsacl ( ds_sd , domain_sid )
fs_sd = security . descriptor . from_sddl ( sddl , security . dom_sid ( domain_sid ) )
2011-08-02 10:13:43 +04:00
2011-12-14 05:18:57 +04:00
# Set ACL
2012-06-19 10:49:33 +04:00
sio = ( security . SECINFO_OWNER |
security . SECINFO_GROUP |
security . SECINFO_DACL |
security . SECINFO_PROTECTED_DACL )
conn . set_acl ( sharepath , fs_sd , sio )
2012-02-25 20:50:14 +04:00
except :
2011-12-14 05:18:57 +04:00
self . samdb . transaction_cancel ( )
2012-02-25 20:50:14 +04:00
raise
else :
self . samdb . transaction_commit ( )
2011-08-02 10:13:43 +04:00
2011-10-13 02:36:44 +04:00
self . outf . write ( " GPO ' %s ' created as %s \n " % ( displayname , gpo ) )
2011-08-02 10:13:43 +04:00
2011-07-14 02:21:19 +04:00
2010-11-28 04:20:15 +03:00
class cmd_gpo ( SuperCommand ) :
2011-08-02 21:50:15 +04:00
""" Group Policy Object (GPO) management """
2010-11-28 04:20:15 +03:00
subcommands = { }
subcommands [ " listall " ] = cmd_listall ( )
2010-11-28 06:33:12 +03:00
subcommands [ " list " ] = cmd_list ( )
2011-07-14 02:21:19 +04:00
subcommands [ " show " ] = cmd_show ( )
subcommands [ " getlink " ] = cmd_getlink ( )
subcommands [ " setlink " ] = cmd_setlink ( )
subcommands [ " dellink " ] = cmd_dellink ( )
subcommands [ " getinheritance " ] = cmd_getinheritance ( )
subcommands [ " setinheritance " ] = cmd_setinheritance ( )
subcommands [ " fetch " ] = cmd_fetch ( )
subcommands [ " create " ] = cmd_create ( )