import sys
import os
+import errno
import tdb
sys.path.insert(0, "bin/python")
from samba import NTSTATUSError
from samba.dcerpc import nbt
from samba import smb
import samba.gpo as gpo
+from tempfile import NamedTemporaryFile
try:
from enum import Enum
gpos = ads.get_gpo_list(creds.get_username())
return gpos
+
+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:
+ dirs = dirs[dirs.index('sysvol')+1:]
+ if not '..' in dirs:
+ return os.path.join(*dirs)
+ raise OSError(path)
+
+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))
+
+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])
+
def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
gp_db = store.get_gplog(creds.get_username())
dc_hostname = get_dc_hostname(creds, lp)
logger.error('Error connecting to \'%s\' using SMB' % dc_hostname)
raise
gpos = get_gpo_list(dc_hostname, creds, lp)
+ try:
+ check_refresh_gpo_list(dc_hostname, lp, creds, gpos)
+ except:
+ logger.error('Failed downloading gpt cache from \'%s\' using SMB' \
+ % dc_hostname)
+ return
for gpo_obj in gpos:
guid = gpo_obj.name
if guid == 'Local Policy':
continue
- path = os.path.join(lp.get('realm').lower(), 'Policies', guid)
- local_path = os.path.join(lp.get("path", "sysvol"), path)
- version = int(gpo.gpo_get_sysvol_gpt_version(local_path)[1])
+ path = os.path.join(lp.get('realm'), 'Policies', guid).upper()
+ version = gpo_version(lp, path)
if version != store.get_int(guid):
logger.info('GPO %s has changed' % guid)
gp_db.state(GPOSTATE.APPLY)
import os
from samba import gpo, tests
from samba.param import LoadParm
+from samba.gpclass import check_refresh_gpo_list, check_safe_path
poldir = r'\\addom.samba.example.com\sysvol\addom.samba.example.com\Policies'
dspath = 'CN=Policies,CN=System,DC=addom,DC=samba,DC=example,DC=com'
def test_gpt_version(self):
global gpt_data
- local_path = self.lp.get("path", "sysvol")
- policies = 'addom.samba.example.com/Policies'
+ local_path = self.lp.cache_path('gpo_cache')
+ policies = 'ADDOM.SAMBA.EXAMPLE.COM/POLICIES'
guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}'
gpo_path = os.path.join(local_path, policies, guid)
old_vers = gpo.gpo_get_sysvol_gpt_version(gpo_path)[1]
self.assertEquals(gpo.gpo_get_sysvol_gpt_version(gpo_path)[1], old_vers,
'gpo_get_sysvol_gpt_version() did not return the expected version')
+ def test_check_refresh_gpo_list(self):
+ cache = self.lp.cache_path('gpo_cache')
+ ads = gpo.ADS_STRUCT(self.server, self.lp, self.creds)
+ if ads.connect():
+ gpos = ads.get_gpo_list(self.creds.get_username())
+ check_refresh_gpo_list(self.server, self.lp, self.creds, gpos)
+
+ self.assertTrue(os.path.exists(cache),
+ 'GPO cache %s was not created' % cache)
+
+ guid = '{31B2F340-016D-11D2-945F-00C04FB984F9}'
+ gpt_ini = os.path.join(cache, 'ADDOM.SAMBA.EXAMPLE.COM/POLICIES',
+ guid, 'GPT.INI')
+ self.assertTrue(os.path.exists(gpt_ini),
+ 'GPT.INI was not cached for %s' % guid)
+
+ def test_check_refresh_gpo_list_malicious_paths(self):
+ # the path cannot contain ..
+ path = '/usr/local/samba/var/locks/sysvol/../../../../../../root/'
+ self.assertRaises(OSError, check_safe_path, path)
+
+ self.assertEqual(check_safe_path('/etc/passwd'), 'etc/passwd')
+ self.assertEqual(check_safe_path('\\\\etc/\\passwd'), 'etc/passwd')
+
+ # there should be no backslashes used to delineate paths
+ before = 'sysvol/addom.samba.example.com\\Policies/' \
+ '{31B2F340-016D-11D2-945F-00C04FB984F9}\\GPT.INI'
+ after = 'addom.samba.example.com/Policies/' \
+ '{31B2F340-016D-11D2-945F-00C04FB984F9}/GPT.INI'
+ result = check_safe_path(before)
+ self.assertEquals(result, after, 'check_safe_path() didn\'t' \
+ ' correctly convert \\ to /')
+