1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-11 05:18:09 +03:00

gpo: Make the gpoupdate script much more reliable

Using a static file blanks the file when samba_gpoupdate crashes. Transformed
to a tdb file and added transactions. Add info logging to monitor gpo changes,
etc. Also handle parse errors and log an error message, then recover. Modified
the parsing code to use ConfigParser. Also, use the backslash in path names
when opening smb files, otherwise it fails against a windows server.

Signed-off-by: David Mulder <dmulder@suse.com>
Reviewed-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
David Mulder 2017-02-11 07:53:07 -07:00 committed by Garming Sam
parent 5194cd4e8d
commit 115615d836
2 changed files with 63 additions and 41 deletions

View File

@ -27,6 +27,8 @@ from samba.samdb import SamDB
from samba.netcmd import gpo as gpo_user
import codecs
from samba import NTSTATUSError
from ConfigParser import ConfigParser
from StringIO import StringIO
class gp_ext(object):
def list(self, rootpath):
@ -42,22 +44,27 @@ class inf_to_ldb(object):
parameter to Samba4. Not registry oriented whatsoever.
'''
def __init__(self, ldb, dn, attribute, val):
def __init__(self, logger, ldb, dn, attribute, val):
self.logger = logger
self.ldb = ldb
self.dn = dn
self.attribute = attribute
self.val = val
def ch_minPwdAge(self, val):
self.logger.info('KDC Minimum Password age was changed from %s to %s' % (self.ldb.get_minPwdAge(), val))
self.ldb.set_minPwdAge(val)
def ch_maxPwdAge(self, val):
self.logger.info('KDC Maximum Password age was changed from %s to %s' % (self.ldb.get_maxPwdAge(), val))
self.ldb.set_maxPwdAge(val)
def ch_minPwdLength(self, val):
self.logger.info('KDC Minimum Password length was changed from %s to %s' % (self.ldb.get_minPwdLength(), val))
self.ldb.set_minPwdLength(val)
def ch_pwdProperties(self, val):
self.logger.info('KDC Password Properties were changed from %s to %s' % (self.ldb.get_pwdProperties(), val))
self.ldb.set_pwdProperties(val)
def explicit(self):
@ -95,6 +102,9 @@ class gp_sec_ext(gp_ext):
count = 0
def __init__(self, logger):
self.logger = logger
def __str__(self):
return "Security GPO extension"
@ -122,7 +132,7 @@ class gp_sec_ext(gp_ext):
ret = False
inftable = self.populate_inf()
policy = conn.loadfile(path).decode('utf-16')
policy = conn.loadfile(path.replace('/', '\\')).decode('utf-16')
current_section = None
LOG = open(attr_log, "a")
LOG.write(str(path.split('/')[2]) + '\n')
@ -133,23 +143,20 @@ class gp_sec_ext(gp_ext):
# If at any point in time a GPO was applied,
# then we return that boolean at the end.
for line in policy.splitlines():
line = line.strip()
if line[0] == '[':
section = line[1: -1]
current_section = inftable.get(section.encode('ascii', 'ignore'))
inf_conf = ConfigParser()
inf_conf.optionxform=str
inf_conf.readfp(StringIO(policy))
else:
# We must be in a section
if not current_section:
continue
(key, value) = line.split("=")
key = key.strip()
for section in inf_conf.sections():
current_section = inftable.get(section)
if not current_section:
continue
for key, value in inf_conf.items(section):
if current_section.get(key):
(att, setter) = current_section.get(key)
value = value.encode('ascii', 'ignore')
ret = True
setter(self.ldb, self.dn, att, value).update_samba()
setter(self.logger, self.ldb, self.dn, att, value).update_samba()
return ret
def parse(self, afile, ldb, conn, attr_log):
@ -174,13 +181,10 @@ class gp_sec_ext(gp_ext):
return None
def scan_log(sysvol_path):
a = open(sysvol_path, "r")
def scan_log(sysvol_tdb):
data = {}
for line in a.readlines():
line = line.strip()
(guid, version) = line.split(" ")
data[guid] = int(version)
for key in sysvol_tdb.iterkeys():
data[key] = sysvol_tdb.get(key)
return data

View File

@ -26,6 +26,7 @@ import fcntl
import sys
import tempfile
import subprocess
import tdb
sys.path.insert(0, "bin/python")
@ -36,6 +37,7 @@ from samba.gpclass import *
from samba.net import Net
from samba.dcerpc import nbt
from samba import smb
import logging
# Finds all GPO Files ending in inf
@ -140,19 +142,6 @@ class GPOServiceSetup:
return self.creds
def GetBackLog(sys_log):
"""Reads BackLog and makes thread aware of which GPO are unchanged or empty
:param String sys_log: path to backLog
:return Dictionary previous_scanned_version: {Unedited GPO: Version Number}
*NOTE on Version below
"""
previous_scanned_version = {}
if os.path.isfile(sys_log):
previous_scanned_version = scan_log(sys_log)
return previous_scanned_version
else:
return None
# Set up the GPO service
GPOService = GPOServiceSetup()
GPOService.InitializeService()
@ -163,18 +152,35 @@ test_ldb = GPOService.Get_LDB()
# Get The lp context
lp = GPOService.Get_lp_Content()
# Set up logging
logger = logging.getLogger('samba_gpoupdate')
logger.addHandler(logging.StreamHandler(sys.stdout))
logger.setLevel(logging.CRITICAL)
log_level = lp.log_level()
if log_level == 1:
logger.setLevel(logging.ERROR)
elif log_level == 2:
logger.setLevel(logging.WARNING)
elif log_level == 3:
logger.setLevel(logging.INFO)
elif log_level >= 4:
logger.setLevel(logging.DEBUG)
# Get the CREDS
creds = GPOService.Get_Creds()
# Read the readable backLog into a hashmap
# then open writable backLog in same location
BackLoggedGPO = None
sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'gpo.tdb')
attr_log = '%s/%s' % (lp.get("path", "sysvol"), 'attrlog.txt')
BackLoggedGPO = GetBackLog(sys_log)
BackLog = open(sys_log, "w")
if os.path.isfile(sys_log):
BackLog = tdb.open(sys_log)
else:
BackLog = tdb.Tdb(sys_log, 0, tdb.DEFAULT, os.O_CREAT|os.O_RDWR)
BackLoggedGPO = scan_log(BackLog)
# We need to know writable DC to setup SMB connection
@ -215,13 +221,18 @@ if (GPO_Deleted):
Reset_Defaults(test_ldb)
GPO_Changed = False
BackLog.transaction_start()
for guid_eval in hierarchy_gpos:
guid = guid_eval[0]
gp_extensions = [gp_sec_ext()]
gp_extensions = [gp_sec_ext(logger)]
local_path = '%s/Policies' % lp.get("realm").lower() + '/' + guid + '/'
version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
version = int(gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1])
try:
old_version = int(BackLoggedGPO.get(guid))
except:
old_version = -1
gpolist = gp_path_list(local_path)
if(version != BackLoggedGPO.get(guid)):
if version != old_version:
GPO_Changed = True
# If the GPO has a dn that is applicable to Samba
if guid_eval[1]:
@ -230,6 +241,13 @@ for guid_eval in hierarchy_gpos:
# If it we have not read it before and is not empty
# Rewrite entire logfile here
if (version != 0) and GPO_Changed == True:
change_backlog = gpo_parser(gpolist, test_ldb, conn, attr_log)
logger.info('GPO %s has changed' % guid)
try:
change_backlog = gpo_parser(gpolist, test_ldb, conn, attr_log)
except:
logger.error('Failed to parse gpo %s' % guid)
continue
BackLog.store(guid, '%i' % version)
BackLog.transaction_commit()
BackLog.close()
BackLog.write('%s %i\n' % (guid, version))