2014-01-31 04:27:05 +04:00
# Reads important GPO parameters and updates Samba
# Copyright (C) Luke Morrison <luc785@.hotmail.com> 2013
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
2018-01-08 17:17:29 +03:00
import errno
2017-05-25 16:27:27 +03:00
import tdb
2014-01-31 04:27:05 +04:00
sys . path . insert ( 0 , " bin/python " )
from samba import NTSTATUSError
2018-09-05 16:59:19 +03:00
from samba . compat import ConfigParser
2018-05-04 13:49:23 +03:00
from samba . compat import StringIO
2017-02-25 00:19:48 +03:00
from abc import ABCMeta , abstractmethod
2017-06-08 20:47:57 +03:00
import xml . etree . ElementTree as etree
2017-11-21 13:44:12 +03:00
import re
2018-03-29 17:32:02 +03:00
from samba . net import Net
from samba . dcerpc import nbt
from samba import smb
import samba . gpo as gpo
2018-06-13 23:45:09 +03:00
from samba . param import LoadParm
from uuid import UUID
2018-01-08 17:17:29 +03:00
from tempfile import NamedTemporaryFile
2017-06-08 20:47:57 +03:00
2017-06-13 01:00:38 +03:00
try :
from enum import Enum
GPOSTATE = Enum ( ' GPOSTATE ' , ' APPLY ENFORCE UNAPPLY ' )
except ImportError :
class GPOSTATE :
APPLY = 1
ENFORCE = 2
UNAPPLY = 3
2018-07-30 09:20:39 +03:00
2017-06-08 20:47:57 +03:00
class gp_log :
''' Log settings overwritten by gpo apply
2017-11-20 00:28:33 +03:00
The gp_log is an xml file that stores a history of gpo changes ( and the
original setting value ) .
2017-06-08 20:47:57 +03:00
The log is organized like so :
< gp >
< user name = " KDC-1$ " >
< applylog >
< guid count = " 0 " value = " { 31B2F340-016D-11D2-945F-00C04FB984F9} " / >
< / applylog >
< guid value = " { 31B2F340-016D-11D2-945F-00C04FB984F9} " >
< gp_ext name = " System Access " >
< attribute name = " minPwdAge " > - 864000000000 < / attribute >
< attribute name = " maxPwdAge " > - 36288000000000 < / attribute >
< attribute name = " minPwdLength " > 7 < / attribute >
< attribute name = " pwdProperties " > 1 < / attribute >
< / gp_ext >
< gp_ext name = " Kerberos Policy " >
< attribute name = " ticket_lifetime " > 1 d < / attribute >
< attribute name = " renew_lifetime " / >
< attribute name = " clockskew " > 300 < / attribute >
< / gp_ext >
< / guid >
< / user >
< / gp >
2017-11-20 00:28:33 +03:00
Each guid value contains a list of extensions , which contain a list of
attributes . The guid value represents a GPO . The attributes are the values
of those settings prior to the application of the GPO .
The list of guids is enclosed within a user name , which represents the user
the settings were applied to . This user may be the samaccountname of the
local computer , which implies that these are machine policies .
The applylog keeps track of the order in which the GPOs were applied , so
that they can be rolled back in reverse , returning the machine to the state
prior to policy application .
2017-06-08 20:47:57 +03:00
'''
def __init__ ( self , user , gpostore , db_log = None ) :
''' Initialize the gp_log
2017-11-20 00:28:33 +03:00
param user - the username ( or machine name ) that policies are
being applied to
param gpostore - the GPOStorage obj which references the tdb which
contains gp_logs
2017-06-08 20:47:57 +03:00
param db_log - ( optional ) a string to initialize the gp_log
'''
2017-06-13 01:00:38 +03:00
self . _state = GPOSTATE . APPLY
2017-06-08 20:47:57 +03:00
self . gpostore = gpostore
self . username = user
if db_log :
self . gpdb = etree . fromstring ( db_log )
else :
self . gpdb = etree . Element ( ' gp ' )
2017-11-20 16:41:19 +03:00
self . user = user
user_obj = self . gpdb . find ( ' user[@name= " %s " ] ' % user )
if user_obj is None :
user_obj = etree . SubElement ( self . gpdb , ' user ' )
user_obj . attrib [ ' name ' ] = user
2017-06-08 20:47:57 +03:00
2017-06-13 01:00:38 +03:00
def state ( self , value ) :
''' Policy application state
param value - APPLY , ENFORCE , or UNAPPLY
2017-11-20 00:28:33 +03:00
The behavior of the gp_log depends on whether we are applying policy ,
enforcing policy , or unapplying policy . During an apply , old settings
are recorded in the log . During an enforce , settings are being applied
but the gp_log does not change . During an unapply , additions to the log
should be ignored ( since function calls to apply settings are actually
2017-06-13 01:00:38 +03:00
reverting policy ) , but removals from the log are allowed .
'''
# If we're enforcing, but we've unapplied, apply instead
if value == GPOSTATE . ENFORCE :
2017-11-20 16:41:19 +03:00
user_obj = self . gpdb . find ( ' user[@name= " %s " ] ' % self . user )
apply_log = user_obj . find ( ' applylog ' )
2017-06-13 01:00:38 +03:00
if apply_log is None or len ( apply_log ) == 0 :
self . _state = GPOSTATE . APPLY
else :
self . _state = value
else :
self . _state = value
2017-06-08 20:47:57 +03:00
def set_guid ( self , guid ) :
''' Log to a different GPO guid
2017-11-20 00:28:33 +03:00
param guid - guid value of the GPO from which we ' re applying
policy
2017-06-08 20:47:57 +03:00
'''
2017-11-20 16:41:19 +03:00
self . guid = guid
user_obj = self . gpdb . find ( ' user[@name= " %s " ] ' % self . user )
obj = user_obj . find ( ' guid[@value= " %s " ] ' % guid )
if obj is None :
obj = etree . SubElement ( user_obj , ' guid ' )
obj . attrib [ ' value ' ] = guid
2017-06-13 01:00:38 +03:00
if self . _state == GPOSTATE . APPLY :
2017-11-20 16:41:19 +03:00
apply_log = user_obj . find ( ' applylog ' )
2017-06-13 01:00:38 +03:00
if apply_log is None :
2017-11-20 16:41:19 +03:00
apply_log = etree . SubElement ( user_obj , ' applylog ' )
2018-05-15 17:37:08 +03:00
prev = apply_log . find ( ' guid[@value= " %s " ] ' % guid )
if prev is None :
item = etree . SubElement ( apply_log , ' guid ' )
2018-07-30 09:18:25 +03:00
item . attrib [ ' count ' ] = ' %d ' % ( len ( apply_log ) - 1 )
2018-05-15 17:37:08 +03:00
item . attrib [ ' value ' ] = guid
2017-06-08 20:47:57 +03:00
def store ( self , gp_ext_name , attribute , old_val ) :
''' Store an attribute in the gp_log
param gp_ext_name - Name of the extension applying policy
param attribute - The attribute being modified
2017-11-20 00:28:33 +03:00
param old_val - The value of the attribute prior to policy
application
2017-06-08 20:47:57 +03:00
'''
2017-06-13 01:00:38 +03:00
if self . _state == GPOSTATE . UNAPPLY or self . _state == GPOSTATE . ENFORCE :
return None
2017-11-20 16:41:19 +03:00
user_obj = self . gpdb . find ( ' user[@name= " %s " ] ' % self . user )
guid_obj = user_obj . find ( ' guid[@value= " %s " ] ' % self . guid )
assert guid_obj is not None , " gpo guid was not set "
ext = guid_obj . find ( ' gp_ext[@name= " %s " ] ' % gp_ext_name )
2017-06-08 20:47:57 +03:00
if ext is None :
2017-11-20 16:41:19 +03:00
ext = etree . SubElement ( guid_obj , ' gp_ext ' )
2017-06-08 20:47:57 +03:00
ext . attrib [ ' name ' ] = gp_ext_name
attr = ext . find ( ' attribute[@name= " %s " ] ' % attribute )
if attr is None :
attr = etree . SubElement ( ext , ' attribute ' )
attr . attrib [ ' name ' ] = attribute
2017-12-01 21:18:55 +03:00
attr . text = old_val
2017-06-08 20:47:57 +03:00
def retrieve ( self , gp_ext_name , attribute ) :
''' Retrieve a stored attribute from the gp_log
param gp_ext_name - Name of the extension which applied policy
param attribute - The attribute being retrieved
2017-11-20 00:28:33 +03:00
return - The value of the attribute prior to policy
application
2017-06-08 20:47:57 +03:00
'''
2017-11-20 16:41:19 +03:00
user_obj = self . gpdb . find ( ' user[@name= " %s " ] ' % self . user )
guid_obj = user_obj . find ( ' guid[@value= " %s " ] ' % self . guid )
assert guid_obj is not None , " gpo guid was not set "
ext = guid_obj . find ( ' gp_ext[@name= " %s " ] ' % gp_ext_name )
2017-06-08 20:47:57 +03:00
if ext is not None :
attr = ext . find ( ' attribute[@name= " %s " ] ' % attribute )
if attr is not None :
return attr . text
return None
2018-05-18 00:56:15 +03:00
def get_applied_guids ( self ) :
''' Return a list of applied ext guids
return - List of guids for gpos that have applied settings
to the system .
'''
guids = [ ]
user_obj = self . gpdb . find ( ' user[@name= " %s " ] ' % self . user )
if user_obj is not None :
apply_log = user_obj . find ( ' applylog ' )
2018-08-29 07:39:51 +03:00
if apply_log is not None :
guid_objs = apply_log . findall ( ' guid[@count] ' )
guids_by_count = [ ( g . get ( ' count ' ) , g . get ( ' value ' ) )
for g in guid_objs ]
guids_by_count . sort ( reverse = True )
guids . extend ( guid for count , guid in guids_by_count )
2018-05-18 00:56:15 +03:00
return guids
def get_applied_settings ( self , guids ) :
''' Return a list of applied ext guids
return - List of tuples containing the guid of a gpo , then
a dictionary of policies and their values prior
policy application . These are sorted so that the
most recently applied settings are removed first .
'''
ret = [ ]
user_obj = self . gpdb . find ( ' user[@name= " %s " ] ' % self . user )
for guid in guids :
guid_settings = user_obj . find ( ' guid[@value= " %s " ] ' % guid )
exts = guid_settings . findall ( ' gp_ext ' )
settings = { }
for ext in exts :
attr_dict = { }
attrs = ext . findall ( ' attribute ' )
for attr in attrs :
attr_dict [ attr . attrib [ ' name ' ] ] = attr . text
settings [ ext . attrib [ ' name ' ] ] = attr_dict
ret . append ( ( guid , settings ) )
return ret
2017-06-08 20:47:57 +03:00
def delete ( self , gp_ext_name , attribute ) :
''' Remove an attribute from the gp_log
2017-11-20 00:28:33 +03:00
param gp_ext_name - name of extension from which to remove the
attribute
2017-06-08 20:47:57 +03:00
param attribute - attribute to remove
'''
2017-11-20 16:41:19 +03:00
user_obj = self . gpdb . find ( ' user[@name= " %s " ] ' % self . user )
guid_obj = user_obj . find ( ' guid[@value= " %s " ] ' % self . guid )
assert guid_obj is not None , " gpo guid was not set "
ext = guid_obj . find ( ' gp_ext[@name= " %s " ] ' % gp_ext_name )
2017-06-08 20:47:57 +03:00
if ext is not None :
attr = ext . find ( ' attribute[@name= " %s " ] ' % attribute )
if attr is not None :
ext . remove ( attr )
if len ( ext ) == 0 :
2017-11-20 16:41:19 +03:00
guid_obj . remove ( ext )
2017-06-08 20:47:57 +03:00
def commit ( self ) :
''' Write gp_log changes to disk '''
self . gpostore . store ( self . username , etree . tostring ( self . gpdb , ' utf-8 ' ) )
2018-07-30 09:20:39 +03:00
2017-06-08 20:47:57 +03:00
class GPOStorage :
def __init__ ( self , log_file ) :
if os . path . isfile ( log_file ) :
self . log = tdb . open ( log_file )
2017-05-25 16:27:27 +03:00
else :
2018-08-29 04:30:59 +03:00
self . log = tdb . Tdb ( log_file , 0 , tdb . DEFAULT , os . O_CREAT | os . O_RDWR )
2017-05-25 16:27:27 +03:00
2017-06-08 20:47:57 +03:00
def start ( self ) :
self . log . transaction_start ( )
def get_int ( self , key ) :
2017-05-25 16:27:27 +03:00
try :
2017-06-08 20:47:57 +03:00
return int ( self . log . get ( key ) )
2017-05-25 16:27:27 +03:00
except TypeError :
2017-06-08 20:47:57 +03:00
return None
def get ( self , key ) :
return self . log . get ( key )
def get_gplog ( self , user ) :
return gp_log ( user , self , self . log . get ( user ) )
def store ( self , key , val ) :
self . log . store ( key , val )
def cancel ( self ) :
self . log . transaction_cancel ( )
2017-05-25 16:27:27 +03:00
2017-06-08 20:47:57 +03:00
def delete ( self , key ) :
self . log . delete ( key )
2017-05-25 16:27:27 +03:00
def commit ( self ) :
2017-06-08 20:47:57 +03:00
self . log . transaction_commit ( )
2017-05-25 16:27:27 +03:00
def __del__ ( self ) :
2017-06-08 20:47:57 +03:00
self . log . close ( )
2017-05-25 16:27:27 +03:00
2018-07-30 09:20:39 +03:00
2014-01-31 04:27:05 +04:00
class gp_ext ( object ) :
2017-02-25 00:19:48 +03:00
__metaclass__ = ABCMeta
2018-05-16 19:58:29 +03:00
def __init__ ( self , logger , lp , creds , store ) :
2018-03-29 18:07:53 +03:00
self . logger = logger
2018-05-16 19:58:29 +03:00
self . lp = lp
self . creds = creds
self . gp_db = store . get_gplog ( creds . get_username ( ) )
2018-03-29 18:07:53 +03:00
2018-05-09 22:16:38 +03:00
@abstractmethod
def process_group_policy ( self , deleted_gpo_list , changed_gpo_list ) :
pass
2017-02-25 00:19:48 +03:00
@abstractmethod
2018-03-29 17:05:21 +03:00
def read ( self , policy ) :
2017-02-25 00:19:48 +03:00
pass
2014-01-31 04:27:05 +04:00
2018-05-16 19:58:29 +03:00
def parse ( self , afile ) :
2018-05-16 19:37:09 +03:00
local_path = self . lp . cache_path ( ' gpo_cache ' )
data_file = os . path . join ( local_path , check_safe_path ( afile ) . upper ( ) )
if os . path . exists ( data_file ) :
return self . read ( open ( data_file , ' r ' ) . read ( ) )
return None
2018-03-29 17:05:21 +03:00
2017-06-08 20:47:57 +03:00
@abstractmethod
def __str__ ( self ) :
pass
2014-01-31 04:27:05 +04:00
2018-07-30 09:20:39 +03:00
2018-07-13 23:45:06 +03:00
class gp_ext_setter ( object ) :
2017-02-25 00:19:48 +03:00
__metaclass__ = ABCMeta
2014-01-31 04:27:05 +04:00
2018-07-13 23:45:06 +03:00
def __init__ ( self , logger , gp_db , lp , creds , attribute , val ) :
2017-02-11 17:53:07 +03:00
self . logger = logger
2014-01-31 04:27:05 +04:00
self . attribute = attribute
self . val = val
2017-02-25 00:19:48 +03:00
self . lp = lp
2018-07-13 23:45:06 +03:00
self . creds = creds
2017-06-08 20:47:57 +03:00
self . gp_db = gp_db
2017-02-25 00:19:48 +03:00
def explicit ( self ) :
return self . val
def update_samba ( self ) :
( upd_sam , value ) = self . mapper ( ) . get ( self . attribute )
upd_sam ( value ( ) )
@abstractmethod
def mapper ( self ) :
pass
2018-07-19 23:10:33 +03:00
def delete ( self ) :
upd_sam , _ = self . mapper ( ) . get ( self . attribute )
upd_sam ( self . val )
2017-06-08 20:47:57 +03:00
@abstractmethod
def __str__ ( self ) :
pass
2018-07-30 09:20:39 +03:00
2018-03-29 17:25:05 +03:00
class gp_inf_ext ( gp_ext ) :
def read ( self , policy ) :
inf_conf = ConfigParser ( )
2018-07-30 09:18:03 +03:00
inf_conf . optionxform = str
2018-03-29 17:25:05 +03:00
try :
inf_conf . readfp ( StringIO ( policy ) )
except :
inf_conf . readfp ( StringIO ( policy . decode ( ' utf-16 ' ) ) )
2018-05-18 01:23:51 +03:00
return inf_conf
2018-03-29 17:25:05 +03:00
2018-07-30 09:21:29 +03:00
2018-03-29 17:32:02 +03:00
''' Fetch the hostname of a writable DC '''
2018-07-30 09:20:39 +03:00
2018-03-29 17:32:02 +03:00
def get_dc_hostname ( creds , lp ) :
net = Net ( creds = creds , lp = lp )
cldap_ret = net . finddc ( domain = lp . get ( ' realm ' ) , flags = ( nbt . NBT_SERVER_LDAP |
2018-07-30 09:16:12 +03:00
nbt . NBT_SERVER_DS ) )
2018-03-29 17:32:02 +03:00
return cldap_ret . pdc_dns_name
2018-07-30 09:21:29 +03:00
2018-03-29 17:32:02 +03:00
''' Fetch a list of GUIDs for applicable GPOs '''
2018-07-30 09:20:39 +03:00
2018-03-29 17:32:02 +03:00
def get_gpo_list ( dc_hostname , creds , lp ) :
gpos = [ ]
ads = gpo . ADS_STRUCT ( dc_hostname , lp , creds )
if ads . connect ( ) :
gpos = ads . get_gpo_list ( creds . get_username ( ) )
return gpos
2018-01-08 17:17:29 +03:00
def cache_gpo_dir ( conn , cache , sub_dir ) :
loc_sub_dir = sub_dir . upper ( )
local_dir = os . path . join ( cache , loc_sub_dir )
try :
os . makedirs ( local_dir , mode = 0o755 )
except OSError as e :
if e . errno != errno . EEXIST :
raise
for fdata in conn . list ( sub_dir ) :
if fdata [ ' attrib ' ] & smb . FILE_ATTRIBUTE_DIRECTORY :
cache_gpo_dir ( conn , cache , os . path . join ( sub_dir , fdata [ ' name ' ] ) )
else :
local_name = fdata [ ' name ' ] . upper ( )
f = NamedTemporaryFile ( delete = False , dir = local_dir )
fname = os . path . join ( sub_dir , fdata [ ' name ' ] ) . replace ( ' / ' , ' \\ ' )
f . write ( conn . loadfile ( fname ) )
f . close ( )
os . rename ( f . name , os . path . join ( local_dir , local_name ) )
def check_safe_path ( path ) :
dirs = re . split ( ' /| \\ \\ ' , path )
if ' sysvol ' in path :
2018-07-30 09:18:25 +03:00
dirs = dirs [ dirs . index ( ' sysvol ' ) + 1 : ]
2018-07-30 09:22:34 +03:00
if ' .. ' not in dirs :
2018-01-08 17:17:29 +03:00
return os . path . join ( * dirs )
raise OSError ( path )
2018-07-30 09:20:39 +03:00
2018-01-08 17:17:29 +03:00
def check_refresh_gpo_list ( dc_hostname , lp , creds , gpos ) :
conn = smb . SMB ( dc_hostname , ' sysvol ' , lp = lp , creds = creds , sign = True )
cache_path = lp . cache_path ( ' gpo_cache ' )
for gpo in gpos :
if not gpo . file_sys_path :
continue
cache_gpo_dir ( conn , cache_path , check_safe_path ( gpo . file_sys_path ) )
2018-07-30 09:20:39 +03:00
2018-05-15 23:00:07 +03:00
def get_deleted_gpos_list ( gp_db , gpos ) :
applied_gpos = gp_db . get_applied_guids ( )
current_guids = set ( [ p . name for p in gpos ] )
deleted_gpos = [ guid for guid in applied_gpos if guid not in current_guids ]
return gp_db . get_applied_settings ( deleted_gpos )
2018-01-08 17:17:29 +03:00
def gpo_version ( lp , path ) :
# gpo.gpo_get_sysvol_gpt_version() reads the GPT.INI from a local file,
# read from the gpo client cache.
gpt_path = lp . cache_path ( os . path . join ( ' gpo_cache ' , path ) )
return int ( gpo . gpo_get_sysvol_gpt_version ( gpt_path ) [ 1 ] )
2018-07-30 09:20:39 +03:00
2018-05-16 18:54:38 +03:00
def apply_gp ( lp , creds , logger , store , gp_extensions , force = False ) :
2018-03-29 17:32:02 +03:00
gp_db = store . get_gplog ( creds . get_username ( ) )
dc_hostname = get_dc_hostname ( creds , lp )
gpos = get_gpo_list ( dc_hostname , creds , lp )
2018-05-15 23:00:07 +03:00
del_gpos = get_deleted_gpos_list ( gp_db , gpos )
2018-01-08 17:17:29 +03:00
try :
check_refresh_gpo_list ( dc_hostname , lp , creds , gpos )
except :
2018-07-30 09:22:01 +03:00
logger . error ( ' Failed downloading gpt cache from \' %s \' using SMB '
2018-07-30 09:16:12 +03:00
% dc_hostname )
2018-01-08 17:17:29 +03:00
return
2018-03-29 17:32:02 +03:00
2018-05-16 18:54:38 +03:00
if force :
changed_gpos = gpos
gp_db . state ( GPOSTATE . ENFORCE )
else :
changed_gpos = [ ]
for gpo_obj in gpos :
if not gpo_obj . file_sys_path :
continue
guid = gpo_obj . name
path = check_safe_path ( gpo_obj . file_sys_path ) . upper ( )
version = gpo_version ( lp , path )
if version != store . get_int ( guid ) :
logger . info ( ' GPO %s has changed ' % guid )
changed_gpos . append ( gpo_obj )
gp_db . state ( GPOSTATE . APPLY )
2018-05-09 22:16:38 +03:00
store . start ( )
for ext in gp_extensions :
try :
2018-05-15 23:00:07 +03:00
ext . process_group_policy ( del_gpos , changed_gpos )
2018-05-09 22:16:38 +03:00
except Exception as e :
logger . error ( ' Failed to apply extension %s ' % str ( ext ) )
logger . error ( ' Message was: ' + str ( e ) )
continue
for gpo_obj in gpos :
if not gpo_obj . file_sys_path :
continue
guid = gpo_obj . name
path = check_safe_path ( gpo_obj . file_sys_path ) . upper ( )
version = gpo_version ( lp , path )
2018-03-29 17:32:02 +03:00
store . store ( guid , ' %i ' % version )
2018-05-09 22:16:38 +03:00
store . commit ( )
2018-03-29 17:32:02 +03:00
2018-07-30 09:20:39 +03:00
2018-07-13 23:45:06 +03:00
def unapply_gp ( lp , creds , logger , store , gp_extensions ) :
2018-03-29 17:32:02 +03:00
gp_db = store . get_gplog ( creds . get_username ( ) )
gp_db . state ( GPOSTATE . UNAPPLY )
2018-05-18 01:48:47 +03:00
# Treat all applied gpos as deleted
del_gpos = gp_db . get_applied_settings ( gp_db . get_applied_guids ( ) )
store . start ( )
for ext in gp_extensions :
try :
ext . process_group_policy ( del_gpos , [ ] )
except Exception as e :
logger . error ( ' Failed to unapply extension %s ' % str ( ext ) )
logger . error ( ' Message was: ' + str ( e ) )
continue
store . commit ( )
2018-03-29 17:32:02 +03:00
2018-07-30 09:20:39 +03:00
2018-06-13 23:45:09 +03:00
def parse_gpext_conf ( smb_conf ) :
lp = LoadParm ( )
if smb_conf is not None :
lp . load ( smb_conf )
else :
lp . load_default ( )
ext_conf = lp . state_path ( ' gpext.conf ' )
parser = ConfigParser ( )
parser . read ( ext_conf )
return lp , parser
2018-07-30 09:20:39 +03:00
2018-06-13 23:45:09 +03:00
def atomic_write_conf ( lp , parser ) :
ext_conf = lp . state_path ( ' gpext.conf ' )
with NamedTemporaryFile ( delete = False , dir = os . path . dirname ( ext_conf ) ) as f :
parser . write ( f )
os . rename ( f . name , ext_conf )
2018-07-30 09:20:39 +03:00
2018-06-13 23:45:09 +03:00
def check_guid ( guid ) :
# Check for valid guid with curly braces
if guid [ 0 ] != ' { ' or guid [ - 1 ] != ' } ' or len ( guid ) != 38 :
return False
try :
UUID ( guid , version = 4 )
except ValueError :
return False
return True
2018-07-30 09:20:39 +03:00
2018-06-13 23:45:09 +03:00
def register_gp_extension ( guid , name , path ,
smb_conf = None , machine = True , user = True ) :
# Check that the module exists
if not os . path . exists ( path ) :
return False
if not check_guid ( guid ) :
return False
lp , parser = parse_gpext_conf ( smb_conf )
2018-07-30 09:22:34 +03:00
if guid not in parser . sections ( ) :
2018-06-13 23:45:09 +03:00
parser . add_section ( guid )
parser . set ( guid , ' DllName ' , path )
parser . set ( guid , ' ProcessGroupPolicy ' , name )
parser . set ( guid , ' NoMachinePolicy ' , 0 if machine else 1 )
parser . set ( guid , ' NoUserPolicy ' , 0 if user else 1 )
atomic_write_conf ( lp , parser )
return True
2018-06-13 23:46:05 +03:00
2018-07-30 09:20:39 +03:00
2018-06-13 23:46:30 +03:00
def list_gp_extensions ( smb_conf = None ) :
_ , parser = parse_gpext_conf ( smb_conf )
results = { }
for guid in parser . sections ( ) :
results [ guid ] = { }
results [ guid ] [ ' DllName ' ] = parser . get ( guid , ' DllName ' )
results [ guid ] [ ' ProcessGroupPolicy ' ] = \
parser . get ( guid , ' ProcessGroupPolicy ' )
results [ guid ] [ ' MachinePolicy ' ] = \
not int ( parser . get ( guid , ' NoMachinePolicy ' ) )
results [ guid ] [ ' UserPolicy ' ] = not int ( parser . get ( guid , ' NoUserPolicy ' ) )
return results
2018-07-30 09:20:39 +03:00
2018-06-13 23:46:05 +03:00
def unregister_gp_extension ( guid , smb_conf = None ) :
if not check_guid ( guid ) :
return False
lp , parser = parse_gpext_conf ( smb_conf )
if guid in parser . sections ( ) :
parser . remove_section ( guid )
atomic_write_conf ( lp , parser )
return True