2010-11-28 04:20:15 +03:00
# implement samba_tool gpo commands
#
# Copyright Andrew Tridgell 2010
2012-07-03 08:20:44 +04:00
# Copyright Amitay Isaacs 2011-2012 <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/>.
#
2018-11-07 01:43:26 +03:00
from __future__ import print_function
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
2018-05-07 07:03:13 +03:00
import re
2018-05-21 08:30:40 +03:00
import xml . etree . ElementTree as ET
import shutil
2019-01-10 06:34:27 +03:00
import tempfile
2010-11-28 04:20:15 +03:00
from samba . auth import system_session
from samba . netcmd import (
Command ,
CommandError ,
Option ,
SuperCommand ,
2018-07-30 09:14:37 +03:00
)
2010-11-28 04:20:15 +03:00
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
2019-01-11 04:53:16 +03:00
from samba . samba3 import param as s3param
2019-01-08 05:10:46 +03:00
from samba . samba3 import libsmb_samba_internal as libsmb
2018-05-21 08:30:40 +03:00
from samba import NTSTATUSError
2011-08-02 10:13:43 +04:00
import uuid
2011-12-07 06:10:10 +04:00
from samba . ntacls import dsacl2fsacl
2012-11-29 12:31:12 +04:00
from samba . dcerpc import nbt
from samba . net import Net
2018-05-29 02:57:26 +03:00
from samba . gp_parse import GPParser , GPNoParserException , GPGeneralizeException
2018-05-23 04:51:08 +03:00
from samba . gp_parse . gp_pol import GPPolParser
2018-06-06 03:57:12 +03:00
from samba . gp_parse . gp_ini import (
GPIniParser ,
GPTIniParser ,
GPFDeploy1IniParser ,
GPScriptsIniParser
)
2018-05-23 04:51:08 +03:00
from samba . gp_parse . gp_csv import GPAuditCsvParser
from samba . gp_parse . gp_inf import GptTmplInfParser
from samba . gp_parse . gp_aas import GPAasParser
2011-07-28 08:07:44 +04:00
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 = [ ]
2019-02-20 03:43:42 +03:00
if gplink . strip ( ) == ' ' :
return ret
2010-11-28 06:33:12 +03:00
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 )
2018-07-30 09:17:14 +03:00
ret . append ( { ' dn ' : d [ 0 ] [ 8 : ] , ' options ' : int ( d [ 1 ] ) } )
2010-11-28 06:33:12 +03:00
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 )
2018-02-14 00:07:23 +03:00
except Exception as 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
2012-11-20 17:58:13 +04:00
def get_gpo_info ( samdb , gpo = None , displayname = None , dn = None ,
2018-08-22 08:06:23 +03:00
sd_flags = ( security . SECINFO_OWNER |
security . SECINFO_GROUP |
security . SECINFO_DACL |
security . SECINFO_SACL ) ) :
2011-07-28 08:07:44 +04:00
''' 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 ,
2018-07-30 09:15:34 +03:00
expression = search_expr ,
attrs = [ ' nTSecurityDescriptor ' ,
' versionNumber ' ,
' flags ' ,
' name ' ,
' displayName ' ,
2019-02-20 06:51:04 +03:00
' gPCFileSysPath ' ,
' gPCMachineExtensionNames ' ,
' gPCUserExtensionNames ' ] ,
2018-07-30 09:15:34 +03:00
controls = [ ' sd_flags:1: %d ' % sd_flags ] )
2018-02-14 00:07:23 +03:00
except Exception as e :
2011-07-28 08:07:44 +04:00
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 ' ] )
2018-02-14 00:07:23 +03:00
except Exception as e :
2012-07-03 08:13:01 +04:00
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 ,
2018-07-30 09:15:34 +03:00
expression = " (objectClass=*) " ,
attrs = [ ' gPLink ' ] ) [ 0 ]
2018-02-14 00:07:23 +03:00
except Exception as e :
2012-07-03 08:55:10 +04:00
raise CommandError ( " Container ' %s ' does not exist " % container_dn , e )
2012-07-03 08:13:01 +04:00
found = False
gpo_dn = str ( get_gpo_dn ( samdb , gpo ) )
if ' gPLink ' in msg :
2018-09-05 16:54:24 +03:00
gplist = parse_gplink ( str ( msg [ ' gPLink ' ] [ 0 ] ) )
2012-07-03 08:13:01 +04:00
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 )
2018-02-14 00:07:23 +03:00
except Exception as e :
2012-07-03 08:13:01 +04:00
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
2018-05-07 07:03:13 +03:00
def find_parser ( name , flags = re . IGNORECASE ) :
2018-05-24 06:17:35 +03:00
if re . match ( ' fdeploy1 \ .ini$ ' , name , flags = flags ) :
return GPFDeploy1IniParser ( )
2018-05-23 04:51:08 +03:00
if re . match ( ' audit \ .csv$ ' , name , flags = flags ) :
return GPAuditCsvParser ( )
if re . match ( ' GptTmpl \ .inf$ ' , name , flags = flags ) :
return GptTmplInfParser ( )
if re . match ( ' GPT \ .INI$ ' , name , flags = flags ) :
return GPTIniParser ( )
2018-06-06 03:57:12 +03:00
if re . match ( ' scripts.ini$ ' , name , flags = flags ) :
return GPScriptsIniParser ( )
if re . match ( ' psscripts.ini$ ' , name , flags = flags ) :
return GPScriptsIniParser ( )
2018-05-23 04:51:08 +03:00
if re . match ( ' .* \ .ini$ ' , name , flags = flags ) :
return GPIniParser ( )
if re . match ( ' .* \ .pol$ ' , name , flags = flags ) :
return GPPolParser ( )
if re . match ( ' .* \ .aas$ ' , name , flags = flags ) :
return GPAasParser ( )
2018-05-07 07:03:13 +03:00
return GPParser ( )
def backup_directory_remote_to_local ( conn , remotedir , localdir ) :
SUFFIX = ' .SAMBABACKUP '
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 , attribs = attr_flags )
2018-09-05 16:54:24 +03:00
dirlist . sort ( key = lambda x : x [ ' name ' ] )
2018-05-07 07:03:13 +03:00
for e in dirlist :
r_name = r_dir + ' \\ ' + e [ ' name ' ]
l_name = os . path . join ( l_dir , e [ ' name ' ] )
2019-01-08 05:10:46 +03:00
if e [ ' attrib ' ] & libsmb . FILE_ATTRIBUTE_DIRECTORY :
2018-05-07 07:03:13 +03:00
r_dirs . append ( r_name )
l_dirs . append ( l_name )
os . mkdir ( l_name )
else :
data = conn . loadfile ( r_name )
2018-09-05 16:54:24 +03:00
with open ( l_name + SUFFIX , ' wb ' ) as f :
2018-05-07 07:03:13 +03:00
f . write ( data )
parser = find_parser ( e [ ' name ' ] )
parser . parse ( data )
parser . write_xml ( l_name + ' .xml ' )
2019-01-08 05:10:46 +03:00
attr_flags = libsmb . FILE_ATTRIBUTE_SYSTEM | \
libsmb . FILE_ATTRIBUTE_DIRECTORY | \
libsmb . FILE_ATTRIBUTE_ARCHIVE | \
libsmb . FILE_ATTRIBUTE_HIDDEN
2011-07-28 08:17:19 +04:00
2018-07-30 09:20:39 +03: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 )
2018-07-30 09:17:02 +03:00
r_dirs = [ remotedir ]
l_dirs = [ localdir ]
2011-07-28 08:17:19 +04:00
while r_dirs :
r_dir = r_dirs . pop ( )
l_dir = l_dirs . pop ( )
2018-05-09 06:24:38 +03:00
dirlist = conn . list ( r_dir , attribs = attr_flags )
2018-09-05 16:54:24 +03:00
dirlist . sort ( key = lambda x : x [ ' name ' ] )
2011-07-28 08:17:19 +04:00
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
2019-01-08 05:10:46 +03:00
if e [ ' attrib ' ] & libsmb . FILE_ATTRIBUTE_DIRECTORY :
2011-07-28 08:17:19 +04:00
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 )
2018-09-05 16:54:24 +03:00
open ( l_name , ' wb ' ) . write ( data )
2011-07-28 08:17:19 +04:00
2018-05-21 08:30:40 +03:00
def copy_directory_local_to_remote ( conn , localdir , remotedir ,
2019-02-26 07:01:19 +03:00
ignore_existing_dir = False ,
keep_existing_files = False ) :
2011-08-02 10:13:01 +04:00
if not conn . chkpath ( remotedir ) :
conn . mkdir ( remotedir )
2018-07-30 09:17:02 +03:00
l_dirs = [ localdir ]
r_dirs = [ remotedir ]
2011-08-02 10:13:01 +04:00
while l_dirs :
l_dir = l_dirs . pop ( )
r_dir = r_dirs . pop ( )
dirlist = os . listdir ( l_dir )
2018-05-07 07:03:13 +03:00
dirlist . sort ( )
2011-08-02 10:13:01 +04:00
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 )
2018-05-21 08:30:40 +03:00
try :
conn . mkdir ( r_name )
except NTSTATUSError :
2019-02-26 07:01:19 +03:00
if not ignore_existing_dir :
2018-05-21 08:30:40 +03:00
raise
2011-08-02 10:13:01 +04:00
else :
2019-02-26 07:01:19 +03:00
if keep_existing_files :
try :
conn . loadfile ( r_name )
continue
except NTSTATUSError :
pass
2018-09-05 16:54:24 +03:00
data = open ( l_name , ' rb ' ) . read ( )
2011-08-02 10:13:01 +04:00
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 )
2018-12-14 00:47:45 +03:00
def smb_connection ( dc_hostname , service , lp , creds , sign = False ) :
# SMB connect to DC
try :
2019-01-11 04:53:16 +03:00
# the SMB bindings rely on having a s3 loadparm
s3_lp = s3param . get_context ( )
s3_lp . load ( lp . configfile )
conn = libsmb . Conn ( dc_hostname , service , lp = s3_lp , creds = creds , sign = sign )
2018-12-14 00:47:45 +03:00
except Exception :
raise CommandError ( " Error connecting to ' %s ' using SMB " % dc_hostname )
return conn
2011-08-02 10:13:01 +04:00
2018-11-07 01:57:13 +03:00
class GPOCommand ( Command ) :
def construct_tmpdir ( self , tmpdir , gpo ) :
""" Ensure that the temporary directory structure used in fetch,
backup , create , and restore is consistent .
If - - tmpdir is used the named directory must be present , which may
contain a ' policy ' subdirectory , but ' policy ' must not itself have
a subdirectory with the gpo name . The policy and gpo directories
will be created .
If - - tmpdir is not used , a temporary directory is securely created .
"""
if tmpdir is None :
tmpdir = tempfile . mkdtemp ( )
print ( " Using temporary directory %s (use --tmpdir to change) " % tmpdir ,
file = self . outf )
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 )
except ( IOError , OSError ) as e :
raise CommandError ( " Error creating teporary GPO directory " , e )
return tmpdir , gpodir
2018-11-07 02:15:12 +03:00
def samdb_connect ( self ) :
''' make a ldap connection to the server '''
try :
self . samdb = SamDB ( url = self . url ,
session_info = system_session ( ) ,
credentials = self . creds , lp = self . lp )
except Exception as e :
raise CommandError ( " LDAP connection to %s failed " % self . url , e )
2018-11-07 01:57:13 +03:00
class cmd_listall ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" List all GPOs. """
2010-11-28 04:20:15 +03:00
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 " )
2018-07-30 09:14:37 +03:00
]
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
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
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
2018-11-07 01:57:13 +03:00
class cmd_list ( GPOCommand ) :
2012-10-08 14:32:58 +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 " ,
2018-07-30 09:16:12 +03:00
type = str , metavar = " URL " , dest = " H " )
2018-07-30 09:14:37 +03:00
]
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 )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2010-11-28 06:33:12 +03:00
try :
2011-07-14 02:21:19 +04:00
msg = self . samdb . search ( expression = ' (&(|(samAccountName= %s )(samAccountName= %s $))(objectClass=User)) ' %
2018-07-30 09:19:05 +03:00
( ldb . binary_encode ( username ) , ldb . binary_encode ( username ) ) )
2011-07-14 02:21:19 +04:00
user_dn = msg [ 0 ] . dn
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " Failed to find account %s " % username )
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 ' ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " Failed to find objectClass for user %s " % username )
2010-11-28 06:33:12 +03:00
2018-07-30 09:16:43 +03:00
session_info_flags = ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
2018-09-03 16:05:48 +03:00
AUTH_SESSION_INFO_AUTHENTICATED )
2011-01-11 10:40:54 +03:00
# 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 :
2018-09-05 16:54:24 +03:00
glist = parse_gplink ( str ( msg [ ' gPLink ' ] [ 0 ] ) )
2010-11-28 06:33:12 +03:00
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 :
2018-08-22 08:06:23 +03:00
sd_flags = ( security . SECINFO_OWNER |
security . SECINFO_GROUP |
security . SECINFO_DACL )
2011-01-13 07:09:03 +03:00
gmsg = self . samdb . search ( base = g [ ' dn ' ] , scope = ldb . SCOPE_BASE ,
2011-07-28 08:07:44 +04:00
attrs = [ ' name ' , ' displayName ' , ' flags ' ,
2012-11-20 17:56:56 +04:00
' nTSecurityDescriptor ' ] ,
controls = [ ' sd_flags:1: %d ' % sd_flags ] )
secdesc_ndr = gmsg [ 0 ] [ ' nTSecurityDescriptor ' ] [ 0 ]
secdesc = ndr_unpack ( security . descriptor , secdesc_ndr )
2011-01-13 07:09:03 +03:00
except Exception :
2012-11-20 17:56:56 +04:00
self . outf . write ( " Failed to fetch gpo object with nTSecurityDescriptor %s \n " %
2018-07-30 09:16:12 +03:00
g [ ' dn ' ] )
2011-01-13 07:09:03 +03:00
continue
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
2018-11-07 01:57:13 +03:00
class cmd_show ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" Show information for a GPO. """
2011-07-14 02:21:19 +04:00
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 )
2018-07-30 09:14:37 +03:00
]
2011-07-14 02:21:19 +04:00
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 )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2011-07-14 02:21:19 +04:00
try :
2011-07-28 08:07:44 +04:00
msg = get_gpo_info ( self . samdb , gpo ) [ 0 ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " GPO ' %s ' does not exist " % gpo )
2011-07-14 02:21:19 +04:00
2012-11-17 10:13:40 +04:00
try :
secdesc_ndr = msg [ ' nTSecurityDescriptor ' ] [ 0 ]
secdesc = ndr_unpack ( security . descriptor , secdesc_ndr )
secdesc_sddl = secdesc . as_sddl ( )
except Exception :
secdesc_sddl = " <hidden> "
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 ) ) ) )
2012-11-17 10:13:40 +04:00
self . outf . write ( " ACL : %s \n " % secdesc_sddl )
2011-10-13 02:36:44 +04:00
self . outf . write ( " \n " )
2011-07-14 02:21:19 +04:00
2018-11-07 01:57:13 +03:00
class cmd_getlink ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" List GPO Links for a container. """
2011-07-14 02:21:19 +04:00
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 )
2018-07-30 09:14:37 +03:00
]
2011-07-14 02:21:19 +04:00
def run ( self , container_dn , H = None , sambaopts = None , credopts = None ,
2018-07-30 09:15:34 +03:00
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 )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2011-07-14 02:21:19 +04:00
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 ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " Container ' %s ' does not exist " % container_dn )
2011-07-14 02:21:19 +04:00
2019-02-20 03:43:42 +03:00
if ' gPLink ' in msg and msg [ ' gPLink ' ] :
2011-10-13 02:36:44 +04:00
self . outf . write ( " GPO(s) linked to DN %s \n " % container_dn )
2018-09-05 16:54:24 +03:00
gplist = parse_gplink ( str ( msg [ ' gPLink ' ] [ 0 ] ) )
2011-07-14 02:21:19 +04:00
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
2018-11-07 01:57:13 +03:00
class cmd_setlink ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" Add or update a GPO link to a container. """
2011-07-14 02:21:19 +04:00
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 ' ,
2018-07-30 09:16:12 +03:00
help = " Disable policy " ) ,
2011-07-14 02:21:19 +04:00
Option ( " --enforce " , dest = " enforced " , default = False , action = ' store_true ' ,
2018-07-30 09:16:12 +03:00
help = " Enforce policy " )
2018-07-30 09:14:37 +03:00
]
2011-07-14 02:21:19 +04:00
2011-07-28 08:07:44 +04:00
def run ( self , container_dn , gpo , H = None , disabled = False , enforced = False ,
2018-07-30 09:15:34 +03:00
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 )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2011-07-14 02:21:19 +04:00
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 ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " GPO ' %s ' does not exist " % gpo )
2012-07-03 05:26:41 +04:00
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 ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " Container ' %s ' does not exist " % container_dn )
2011-07-14 02:21:19 +04:00
# Update existing GPlinks or Add new one
existing_gplink = False
if ' gPLink ' in msg :
2018-09-05 16:54:24 +03:00
gplist = parse_gplink ( str ( msg [ ' gPLink ' ] [ 0 ] ) )
2011-07-14 02:21:19 +04:00
existing_gplink = True
found = False
for g in gplist :
if g [ ' dn ' ] . lower ( ) == gpo_dn . lower ( ) :
g [ ' options ' ] = gplink_options
found = True
break
2012-07-03 08:55:10 +04:00
if found :
raise CommandError ( " GPO ' %s ' already linked to this container " % gpo )
else :
2018-07-30 09:17:14 +03:00
gplist . insert ( 0 , { ' dn ' : gpo_dn , ' options ' : gplink_options } )
2011-07-14 02:21:19 +04:00
else :
gplist = [ ]
2018-07-30 09:17:14 +03:00
gplist . append ( { ' dn ' : gpo_dn , ' options ' : gplink_options } )
2011-07-14 02:21:19 +04:00
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 )
2018-02-14 00:07:23 +03:00
except Exception as 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 )
2018-11-07 01:57:13 +03:00
class cmd_dellink ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" Delete GPO link from a container. """
2011-07-14 02:21:19 +04:00
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 ) ,
2018-07-30 09:14:37 +03:00
]
2011-07-14 02:21:19 +04:00
2012-07-03 08:16:41 +04:00
def run ( self , container , gpo , H = None , sambaopts = None , credopts = None ,
2018-07-30 09:15:34 +03:00
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 )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2011-07-14 02:21:19 +04:00
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 ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " GPO ' %s ' does not exist " % gpo )
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 )
2018-11-07 01:57:13 +03:00
class cmd_listcontainers ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" List all linked containers for a GPO. """
2012-07-03 08:22:42 +04:00
synopsis = " % prog <gpo> [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
takes_args = [ ' gpo ' ]
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str )
2018-07-30 09:14:37 +03:00
]
2012-07-03 08:22:42 +04:00
def run ( self , gpo , H = None , sambaopts = None , credopts = None ,
2018-07-30 09:15:34 +03:00
versionopts = None ) :
2012-07-03 08:22:42 +04:00
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
self . url = dc_url ( self . lp , self . creds , H )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2012-07-03 08:22:42 +04:00
msg = get_gpo_containers ( self . samdb , gpo )
if len ( msg ) :
self . outf . write ( " Container(s) using GPO %s \n " % gpo )
for m in msg :
self . outf . write ( " DN: %s \n " % m [ ' dn ' ] )
else :
self . outf . write ( " No Containers using GPO %s \n " % gpo )
2018-11-07 01:57:13 +03:00
class cmd_getinheritance ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" Get inheritance flag for a container. """
2011-07-14 02:21:19 +04:00
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 )
2018-07-30 09:14:37 +03:00
]
2011-07-14 02:21:19 +04:00
def run ( self , container_dn , H = None , sambaopts = None , credopts = None ,
2018-07-30 09:15:34 +03:00
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 )
2012-07-03 08:17:48 +04:00
self . url = dc_url ( self . lp , self . creds , H )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
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 ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " Container ' %s ' does not exist " % container_dn )
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
2018-11-07 01:57:13 +03:00
class cmd_setinheritance ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" Set inheritance flag on a container. """
2011-07-14 02:21:19 +04:00
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 ,
}
2018-07-30 09:17:02 +03:00
takes_args = [ ' container_dn ' , ' inherit_state ' ]
2011-07-14 02:21:19 +04:00
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str )
2018-07-30 09:14:37 +03:00
]
2011-07-14 02:21:19 +04:00
def run ( self , container_dn , inherit_state , H = None , sambaopts = None , credopts = None ,
2018-07-30 09:15:34 +03:00
versionopts = None ) :
2011-07-14 02:21:19 +04:00
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
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
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 ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " Container ' %s ' does not exist " % container_dn )
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 )
2018-02-14 00:07:23 +03:00
except Exception as 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
2018-11-07 01:57:13 +03:00
class cmd_fetch ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" Download a GPO. """
2011-07-14 02:21:19 +04:00
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 )
2018-07-30 09:14:37 +03:00
]
2011-07-28 08:17:19 +04:00
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
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2011-07-28 08:17:19 +04:00
try :
msg = get_gpo_info ( self . samdb , gpo ) [ 0 ]
2012-07-03 08:55:10 +04:00
except Exception :
raise CommandError ( " GPO ' %s ' does not exist " % gpo )
2011-07-28 08:17:19 +04:00
2011-08-01 09:47:10 +04:00
# verify UNC path
2018-09-05 16:54:24 +03:00
unc = str ( msg [ ' gPCFileSysPath ' ] [ 0 ] )
2011-07-28 08:17:19 +04:00
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
2018-12-14 00:47:45 +03:00
conn = smb_connection ( dc_hostname , service , lp = self . lp ,
creds = self . creds , sign = True )
2011-07-28 08:17:19 +04:00
2011-08-01 09:47:10 +04:00
# Copy GPT
2018-11-07 01:57:13 +03:00
tmpdir , gpodir = self . construct_tmpdir ( tmpdir , gpo )
2011-07-28 08:17:19 +04:00
try :
2011-08-01 09:47:10 +04:00
copy_directory_remote_to_local ( conn , sharepath , gpodir )
2018-02-14 00:07:23 +03:00
except Exception as 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
2018-11-07 01:57:13 +03:00
class cmd_backup ( GPOCommand ) :
2018-05-07 07:03:13 +03:00
""" Backup a GPO. """
synopsis = " % prog <gpo> [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
takes_args = [ ' gpo ' ]
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str ) ,
2018-05-29 02:57:26 +03:00
Option ( " --tmpdir " , help = " Temporary directory for copying policy files " , type = str ) ,
Option ( " --generalize " , help = " Generalize XML entities to restore " ,
default = False , action = ' store_true ' ) ,
Option ( " --entities " , help = " File to export defining XML entities for the restore " ,
dest = ' ent_file ' , type = str )
2018-09-03 16:05:31 +03:00
]
2018-05-07 07:03:13 +03:00
2018-05-29 02:57:26 +03:00
def run ( self , gpo , H = None , tmpdir = None , generalize = False , sambaopts = None ,
credopts = None , versionopts = None , ent_file = None ) :
2018-05-07 07:03:13 +03:00
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
# 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 )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2018-05-07 07:03:13 +03:00
try :
msg = get_gpo_info ( self . samdb , gpo ) [ 0 ]
except Exception :
raise CommandError ( " GPO ' %s ' does not exist " % gpo )
# verify UNC path
2018-09-05 16:54:24 +03:00
unc = str ( msg [ ' gPCFileSysPath ' ] [ 0 ] )
2018-05-07 07:03:13 +03:00
try :
[ dom_name , service , sharepath ] = parse_unc ( unc )
except ValueError :
raise CommandError ( " Invalid GPO path ( %s ) " % unc )
# SMB connect to DC
2018-12-14 00:47:45 +03:00
conn = smb_connection ( dc_hostname , service , lp = self . lp ,
creds = self . creds )
2018-05-07 07:03:13 +03:00
# Copy GPT
2018-11-07 01:57:13 +03:00
tmpdir , gpodir = self . construct_tmpdir ( tmpdir , gpo )
2018-05-07 07:03:13 +03:00
try :
backup_directory_remote_to_local ( conn , sharepath , gpodir )
except Exception as e :
# FIXME: Catch more specific exception
raise CommandError ( " Error copying GPO from DC " , e )
2018-05-29 02:57:26 +03:00
2018-05-07 07:03:13 +03:00
self . outf . write ( ' GPO copied to %s \n ' % gpodir )
2018-05-29 02:57:26 +03:00
if generalize :
self . outf . write ( ' \n Attempting to generalize XML entities: \n ' )
entities = cmd_backup . generalize_xml_entities ( self . outf , gpodir ,
gpodir )
import operator
ents = ' '
for ent in sorted ( entities . items ( ) , key = operator . itemgetter ( 1 ) ) :
ents + = ' <!ENTITY {} " {} " > \n ' . format ( ent [ 1 ] . strip ( ' &; ' ) , ent [ 0 ] )
if ent_file :
with open ( ent_file , ' w ' ) as f :
f . write ( ents )
self . outf . write ( ' Entities successfully written to %s \n ' %
ent_file )
else :
self . outf . write ( ' \n Entities: \n ' )
self . outf . write ( ents )
2019-02-20 06:51:04 +03:00
# Backup the enabled GPO extension names
for ext in ( ' gPCMachineExtensionNames ' , ' gPCUserExtensionNames ' ) :
if ext in msg :
with open ( os . path . join ( gpodir , ext + ' .SAMBAEXT ' ) , ' wb ' ) as f :
f . write ( msg [ ext ] [ 0 ] )
2018-05-29 02:57:26 +03:00
@staticmethod
def generalize_xml_entities ( outf , sourcedir , targetdir ) :
entities = { }
if not os . path . exists ( targetdir ) :
os . mkdir ( targetdir )
l_dirs = [ sourcedir ]
r_dirs = [ targetdir ]
while l_dirs :
l_dir = l_dirs . pop ( )
r_dir = r_dirs . pop ( )
dirlist = os . listdir ( l_dir )
dirlist . sort ( )
for e in dirlist :
l_name = os . path . join ( l_dir , e )
r_name = os . path . join ( r_dir , e )
if os . path . isdir ( l_name ) :
l_dirs . append ( l_name )
r_dirs . append ( r_name )
if not os . path . exists ( r_name ) :
os . mkdir ( r_name )
else :
if l_name . endswith ( ' .xml ' ) :
# Restore the xml file if possible
# Get the filename to find the parser
to_parse = os . path . basename ( l_name ) [ : - 4 ]
parser = find_parser ( to_parse )
try :
with open ( l_name , ' r ' ) as ltemp :
data = ltemp . read ( )
concrete_xml = ET . fromstring ( data )
found_entities = parser . generalize_xml ( concrete_xml , r_name , entities )
except GPGeneralizeException :
outf . write ( ' SKIPPING: Generalizing failed for %s \n ' % to_parse )
else :
# No need to generalize non-xml files.
#
# TODO This could be improved with xml files stored in
# the renamed backup file (with custom extension) by
# inlining them into the exported backups.
if not os . path . samefile ( l_name , r_name ) :
shutil . copy2 ( l_name , r_name )
return entities
2018-05-07 07:03:13 +03:00
2018-11-07 01:57:13 +03:00
class cmd_create ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" Create an empty GPO. """
2011-08-02 10:13:43 +04:00
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 )
2018-07-30 09:14:37 +03:00
]
2011-08-02 10:13:43 +04:00
2012-09-27 20:30:47 +04:00
def run ( self , displayname , H = None , tmpdir = None , sambaopts = None , credopts = None ,
2011-08-02 10:13:43 +04:00
versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2012-11-29 12:31:12 +04:00
net = Net ( creds = self . creds , lp = self . lp )
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
2012-11-29 12:31:12 +04:00
flags = ( nbt . NBT_SERVER_LDAP |
nbt . NBT_SERVER_DS |
nbt . NBT_SERVER_WRITABLE )
cldap_ret = net . finddc ( address = dc_hostname , flags = flags )
2012-07-03 08:17:48 +04:00
else :
2012-11-29 12:31:12 +04:00
flags = ( nbt . NBT_SERVER_LDAP |
nbt . NBT_SERVER_DS |
nbt . NBT_SERVER_WRITABLE )
cldap_ret = net . finddc ( domain = self . lp . get ( ' realm ' ) , flags = flags )
dc_hostname = cldap_ret . pdc_dns_name
2012-07-03 08:17:48 +04:00
self . url = dc_url ( self . lp , self . creds , dc = dc_hostname )
2011-08-02 10:13:43 +04:00
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2011-08-02 10:13:43 +04:00
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 ( )
2018-05-21 08:30:40 +03:00
self . gpo_name = gpo
2012-11-29 12:31:12 +04:00
realm = cldap_ret . dns_domain
2011-08-02 10:13:43 +04:00
unc_path = " \\ \\ %s \\ sysvol \\ %s \\ Policies \\ %s " % ( realm , realm , gpo )
# Create GPT
2018-11-07 01:57:13 +03:00
self . tmpdir , gpodir = self . construct_tmpdir ( tmpdir , gpo )
2018-05-21 08:30:40 +03:00
self . gpodir = gpodir
2011-08-02 10:13:43 +04:00
try :
os . mkdir ( os . path . join ( gpodir , " Machine " ) )
os . mkdir ( os . path . join ( gpodir , " User " ) )
gpt_contents = " [General] \r \n Version=0 \r \n "
2018-04-11 07:03:34 +03:00
open ( os . path . join ( gpodir , " GPT.INI " ) , " w " ) . write ( gpt_contents )
2018-02-14 00:07:23 +03:00
except Exception as e :
2012-09-27 20:30:47 +04:00
raise CommandError ( " Error Creating GPO files " , e )
2011-08-02 10:13:43 +04:00
2011-12-14 05:18:57 +04:00
# Connect to DC over SMB
[ dom_name , service , sharepath ] = parse_unc ( unc_path )
2018-05-21 08:30:40 +03:00
self . sharepath = sharepath
2018-12-14 00:47:45 +03:00
conn = smb_connection ( dc_hostname , service , lp = self . lp ,
creds = self . creds )
2011-08-02 10:13:43 +04:00
2018-05-21 08:30:40 +03:00
self . conn = conn
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 " )
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 " )
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 " )
self . samdb . add ( m )
2011-08-02 10:13:43 +04:00
2011-12-14 05:18:57 +04:00
# Get new security descriptor
2018-07-30 09:16:43 +03:00
ds_sd_flags = ( security . SECINFO_OWNER |
2018-09-03 16:05:48 +03:00
security . SECINFO_GROUP |
security . SECINFO_DACL )
2012-11-29 12:31:12 +04:00
msg = get_gpo_info ( self . samdb , gpo = gpo , sd_flags = ds_sd_flags ) [ 0 ]
2012-11-20 17:51:46 +04:00
ds_sd_ndr = msg [ ' nTSecurityDescriptor ' ] [ 0 ]
2011-12-14 05:18:57 +04:00
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-11-05 13:44:14 +04:00
domain_sid = security . dom_sid ( self . samdb . get_domain_sid ( ) )
2012-06-19 10:49:33 +04:00
sddl = dsacl2fsacl ( ds_sd , domain_sid )
2012-11-05 13:44:14 +04:00
fs_sd = security . descriptor . from_sddl ( sddl , domain_sid )
2011-08-02 10:13:43 +04:00
2012-11-29 12:31:12 +04:00
# Copy GPO directory
create_directory_hier ( conn , sharepath )
2011-12-14 05:18:57 +04:00
# Set ACL
2018-07-30 09:16:43 +03:00
sio = ( security . SECINFO_OWNER |
2018-09-03 16:05:48 +03:00
security . SECINFO_GROUP |
security . SECINFO_DACL |
security . SECINFO_PROTECTED_DACL )
2012-06-19 10:49:33 +04:00
conn . set_acl ( sharepath , fs_sd , sio )
2012-11-29 12:31:12 +04:00
# Copy GPO files over SMB
copy_directory_local_to_remote ( conn , gpodir , sharepath )
m = ldb . Message ( )
m . dn = gpo_dn
m [ ' a02 ' ] = ldb . MessageElement ( displayname , ldb . FLAG_MOD_REPLACE , " displayName " )
m [ ' a03 ' ] = ldb . MessageElement ( unc_path , ldb . FLAG_MOD_REPLACE , " gPCFileSysPath " )
m [ ' a05 ' ] = ldb . MessageElement ( " 0 " , ldb . FLAG_MOD_REPLACE , " versionNumber " )
m [ ' a07 ' ] = ldb . MessageElement ( " 2 " , ldb . FLAG_MOD_REPLACE , " gpcFunctionalityVersion " )
m [ ' a04 ' ] = ldb . MessageElement ( " 0 " , ldb . FLAG_MOD_REPLACE , " flags " )
2018-07-30 09:18:03 +03:00
controls = [ " permissive_modify:0 " ]
2012-11-29 12:31:12 +04:00
self . samdb . modify ( m , controls = controls )
2012-07-03 08:55:10 +04:00
except Exception :
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
2018-05-21 08:30:40 +03:00
class cmd_restore ( cmd_create ) :
""" Restore a GPO to a new container. """
synopsis = " % prog <displayname> <backup location> [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
takes_args = [ ' displayname ' , ' backup ' ]
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 ) ,
2019-02-26 07:01:19 +03:00
Option ( " --entities " , help = " File defining XML entities to insert into DOCTYPE header " , type = str ) ,
Option ( " --restore-metadata " , help = " Keep the old GPT.INI file and associated version number " ,
default = False , action = " store_true " )
2018-09-03 16:05:31 +03:00
]
2018-05-21 08:30:40 +03:00
def restore_from_backup_to_local_dir ( self , sourcedir , targetdir , dtd_header = ' ' ) :
SUFFIX = ' .SAMBABACKUP '
if not os . path . exists ( targetdir ) :
os . mkdir ( targetdir )
l_dirs = [ sourcedir ]
r_dirs = [ targetdir ]
while l_dirs :
l_dir = l_dirs . pop ( )
r_dir = r_dirs . pop ( )
dirlist = os . listdir ( l_dir )
2018-05-29 02:57:26 +03:00
dirlist . sort ( )
2018-05-21 08:30:40 +03:00
for e in dirlist :
l_name = os . path . join ( l_dir , e )
r_name = os . path . join ( r_dir , e )
if os . path . isdir ( l_name ) :
l_dirs . append ( l_name )
r_dirs . append ( r_name )
if not os . path . exists ( r_name ) :
os . mkdir ( r_name )
else :
if l_name . endswith ( ' .xml ' ) :
# Restore the xml file if possible
# Get the filename to find the parser
to_parse = os . path . basename ( l_name ) [ : - 4 ]
parser = find_parser ( to_parse )
try :
with open ( l_name , ' r ' ) as ltemp :
data = ltemp . read ( )
2018-06-12 07:19:41 +03:00
xml_head = ' <?xml version= " 1.0 " encoding= " utf-8 " ?> '
if data . startswith ( xml_head ) :
# It appears that sometimes the DTD rejects
# the xml header being after it.
data = data [ len ( xml_head ) : ]
# Load the XML file with the DTD (entity) header
parser . load_xml ( ET . fromstring ( xml_head + dtd_header + data ) )
else :
parser . load_xml ( ET . fromstring ( dtd_header + data ) )
2018-05-21 08:30:40 +03:00
# Write out the substituted files in the output
# location, ready to copy over.
parser . write_binary ( r_name [ : - 4 ] )
except GPNoParserException :
# In the failure case, we fallback
original_file = l_name [ : - 4 ] + SUFFIX
shutil . copy2 ( original_file , r_name [ : - 4 ] )
self . outf . write ( ' WARNING: No such parser for %s \n ' % to_parse )
self . outf . write ( ' WARNING: Falling back to simple copy-restore. \n ' )
except :
import traceback
traceback . print_exc ( )
# In the failure case, we fallback
original_file = l_name [ : - 4 ] + SUFFIX
shutil . copy2 ( original_file , r_name [ : - 4 ] )
self . outf . write ( ' WARNING: Error during parsing for %s \n ' % l_name )
self . outf . write ( ' WARNING: Falling back to simple copy-restore. \n ' )
def run ( self , displayname , backup , H = None , tmpdir = None , entities = None , sambaopts = None , credopts = None ,
2019-02-26 07:01:19 +03:00
versionopts = None , restore_metadata = None ) :
2018-05-21 08:30:40 +03:00
dtd_header = ' '
if not os . path . exists ( backup ) :
raise CommandError ( " Backup directory does not exist %s " % backup )
if entities is not None :
# DOCTYPE name is meant to match root element, but ElementTree does
# not seem to care, so this seems to be enough.
dtd_header = ' <!DOCTYPE foobar [ \n '
if not os . path . exists ( entities ) :
raise CommandError ( " Entities file does not exist %s " %
entities )
with open ( entities , ' r ' ) as entities_file :
entities_content = entities_file . read ( )
# Do a basic regex test of the entities file format
if re . match ( ' ( \ s*<!ENTITY \ s*[a-zA-Z0-9_]+ \ s*.*?>)+ \ s* \ Z ' ,
entities_content , flags = re . MULTILINE ) is None :
raise CommandError ( " Entities file does not appear to "
" conform to format \n "
' e.g. <!ENTITY entity " value " > ' )
dtd_header + = entities_content . strip ( )
dtd_header + = ' \n ]> \n '
super ( cmd_restore , self ) . run ( displayname , H , tmpdir , sambaopts ,
2018-09-03 16:05:52 +03:00
credopts , versionopts )
2018-05-21 08:30:40 +03:00
try :
# Iterate over backup files and restore with DTD
self . restore_from_backup_to_local_dir ( backup , self . gpodir ,
dtd_header )
2019-02-26 07:01:19 +03:00
keep_new_files = not restore_metadata
2018-05-21 08:30:40 +03:00
# Copy GPO files over SMB
copy_directory_local_to_remote ( self . conn , self . gpodir ,
self . sharepath ,
2019-02-26 07:01:19 +03:00
ignore_existing_dir = True ,
keep_existing_files = keep_new_files )
2018-05-21 08:30:40 +03:00
2019-02-20 06:51:04 +03:00
gpo_dn = get_gpo_dn ( self . samdb , self . gpo_name )
# Restore the enabled extensions
for ext in ( ' gPCMachineExtensionNames ' , ' gPCUserExtensionNames ' ) :
ext_file = os . path . join ( backup , ext + ' .SAMBAEXT ' )
if os . path . exists ( ext_file ) :
with open ( ext_file , ' rb ' ) as f :
data = f . read ( )
m = ldb . Message ( )
m . dn = gpo_dn
m [ ext ] = ldb . MessageElement ( data , ldb . FLAG_MOD_REPLACE ,
ext )
self . samdb . modify ( m )
2018-05-21 08:30:40 +03:00
except Exception as e :
import traceback
traceback . print_exc ( )
self . outf . write ( str ( e ) + ' \n ' )
self . outf . write ( " Failed to restore GPO -- deleting... \n " )
cmd = cmd_del ( )
cmd . run ( self . gpo_name , H , sambaopts , credopts , versionopts )
raise CommandError ( " Failed to restore: %s " % e )
2018-11-07 01:57:13 +03:00
class cmd_del ( GPOCommand ) :
2012-10-08 14:32:58 +04:00
""" Delete a GPO. """
2012-07-03 08:23:48 +04:00
synopsis = " % prog <gpo> [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
takes_args = [ ' gpo ' ]
takes_options = [
Option ( " -H " , help = " LDB URL for database or target server " , type = str ) ,
2018-07-30 09:14:37 +03:00
]
2012-07-03 08:23:48 +04:00
def run ( self , gpo , H = None , sambaopts = None , credopts = None ,
2018-07-30 09:15:34 +03:00
versionopts = None ) :
2012-07-03 08:23:48 +04:00
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
# 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 )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2012-07-03 08:23:48 +04:00
# Check if valid GPO
try :
2012-11-29 12:31:12 +04:00
msg = get_gpo_info ( self . samdb , gpo = gpo ) [ 0 ]
2018-09-05 16:54:24 +03:00
unc_path = str ( msg [ ' gPCFileSysPath ' ] [ 0 ] )
2012-07-03 08:23:48 +04:00
except Exception :
2012-07-03 08:55:10 +04:00
raise CommandError ( " GPO ' %s ' does not exist " % gpo )
2012-07-03 08:23:48 +04:00
# Connect to DC over SMB
[ dom_name , service , sharepath ] = parse_unc ( unc_path )
2018-12-14 00:47:45 +03:00
conn = smb_connection ( dc_hostname , service , lp = self . lp ,
creds = self . creds )
2012-07-03 08:23:48 +04:00
self . samdb . transaction_start ( )
try :
# Check for existing links
msg = get_gpo_containers ( self . samdb , gpo )
if len ( msg ) :
self . outf . write ( " GPO %s is linked to containers \n " % gpo )
for m in msg :
del_gpo_link ( self . samdb , m [ ' dn ' ] , gpo )
self . outf . write ( " Removed link from %s . \n " % m [ ' dn ' ] )
# Remove LDAP entries
gpo_dn = get_gpo_dn ( self . samdb , gpo )
self . samdb . delete ( ldb . Dn ( self . samdb , " CN=User, %s " % str ( gpo_dn ) ) )
self . samdb . delete ( ldb . Dn ( self . samdb , " CN=Machine, %s " % str ( gpo_dn ) ) )
self . samdb . delete ( gpo_dn )
# Remove GPO files
conn . deltree ( sharepath )
except Exception :
self . samdb . transaction_cancel ( )
raise
else :
self . samdb . transaction_commit ( )
self . outf . write ( " GPO %s deleted. \n " % gpo )
2018-11-07 01:57:13 +03:00
class cmd_aclcheck ( GPOCommand ) :
2012-11-05 12:36:28 +04:00
""" Check all GPOs have matching LDAP and DS ACLs. """
synopsis = " % prog [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
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
]
2012-11-05 12:36:28 +04:00
def run ( self , H = None , sambaopts = None , credopts = None , versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
self . url = dc_url ( self . lp , self . creds , H )
# 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 )
2018-11-07 02:15:12 +03:00
self . samdb_connect ( )
2012-11-05 12:36:28 +04:00
msg = get_gpo_info ( self . samdb , None )
for m in msg :
# verify UNC path
2018-09-05 16:54:24 +03:00
unc = str ( m [ ' gPCFileSysPath ' ] [ 0 ] )
2012-11-05 12:36:28 +04:00
try :
[ dom_name , service , sharepath ] = parse_unc ( unc )
except ValueError :
raise CommandError ( " Invalid GPO path ( %s ) " % unc )
# SMB connect to DC
2018-12-14 00:47:45 +03:00
conn = smb_connection ( dc_hostname , service , lp = self . lp ,
creds = self . creds )
2012-11-05 12:36:28 +04:00
fs_sd = conn . get_acl ( sharepath , security . SECINFO_OWNER | security . SECINFO_GROUP | security . SECINFO_DACL , security . SEC_FLAG_MAXIMUM_ALLOWED )
2019-01-29 03:25:55 +03:00
if ' nTSecurityDescriptor ' not in m :
raise CommandError ( " Could not read nTSecurityDescriptor. "
" This requires an Administrator account " )
2012-11-20 17:51:46 +04:00
ds_sd_ndr = m [ ' nTSecurityDescriptor ' ] [ 0 ]
2012-11-05 12:36:28 +04:00
ds_sd = ndr_unpack ( security . descriptor , ds_sd_ndr ) . as_sddl ( )
# Create a file system security descriptor
domain_sid = security . dom_sid ( self . samdb . get_domain_sid ( ) )
expected_fs_sddl = dsacl2fsacl ( ds_sd , domain_sid )
if ( fs_sd . as_sddl ( domain_sid ) != expected_fs_sddl ) :
raise CommandError ( " Invalid GPO ACL %s on path ( %s ), should be %s " % ( fs_sd . as_sddl ( domain_sid ) , sharepath , expected_fs_sddl ) )
2010-11-28 04:20:15 +03:00
class cmd_gpo ( SuperCommand ) :
2012-10-09 13:53:21 +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 ( )
2012-07-03 08:22:42 +04:00
subcommands [ " listcontainers " ] = cmd_listcontainers ( )
2011-07-14 02:21:19 +04:00
subcommands [ " getinheritance " ] = cmd_getinheritance ( )
subcommands [ " setinheritance " ] = cmd_setinheritance ( )
subcommands [ " fetch " ] = cmd_fetch ( )
subcommands [ " create " ] = cmd_create ( )
2012-07-03 08:23:48 +04:00
subcommands [ " del " ] = cmd_del ( )
2012-11-05 12:36:28 +04:00
subcommands [ " aclcheck " ] = cmd_aclcheck ( )
2018-05-07 07:03:13 +03:00
subcommands [ " backup " ] = cmd_backup ( )
2018-05-21 08:30:40 +03:00
subcommands [ " restore " ] = cmd_restore ( )