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:
parent
5194cd4e8d
commit
115615d836
@ -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
|
||||
|
||||
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user