mirror of
https://github.com/samba-team/samba.git
synced 2025-01-11 05:18:09 +03:00
gpo: Initial commit for GPO work
Enclosed is my Summer of Code 2013 patch to have vital password GPO always applied to the Samba4 Domain Controller using a GPO update service. To try it out "make -j" your samba with the patch, apply a security password GPO and see the difference in ~20 seconds. It also takes GPO hierarchy into account. Split from "Initial commit for GPO work done by Luke Morrison" by David Mulder Signed-off-by: Garming Sam <garming@catalyst.net.nz> Signed-off-by: Luke Morrison <luke@hubtrek.com> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
148b7ae707
commit
5194cd4e8d
315
python/samba/gpclass.py
Normal file
315
python/samba/gpclass.py
Normal file
@ -0,0 +1,315 @@
|
||||
# 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
|
||||
sys.path.insert(0, "bin/python")
|
||||
import samba.gpo as gpo
|
||||
import optparse
|
||||
import ldb
|
||||
from samba.auth import system_session
|
||||
import samba.getopt as options
|
||||
from samba.samdb import SamDB
|
||||
from samba.netcmd import gpo as gpo_user
|
||||
import codecs
|
||||
from samba import NTSTATUSError
|
||||
|
||||
class gp_ext(object):
|
||||
def list(self, rootpath):
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
return "default_gp_ext"
|
||||
|
||||
|
||||
class inf_to_ldb(object):
|
||||
'''This class takes the .inf file parameter (essentially a GPO file mapped to a GUID),
|
||||
hashmaps it to the Samba parameter, which then uses an ldb object to update the
|
||||
parameter to Samba4. Not registry oriented whatsoever.
|
||||
'''
|
||||
|
||||
def __init__(self, ldb, dn, attribute, val):
|
||||
self.ldb = ldb
|
||||
self.dn = dn
|
||||
self.attribute = attribute
|
||||
self.val = val
|
||||
|
||||
def ch_minPwdAge(self, val):
|
||||
self.ldb.set_minPwdAge(val)
|
||||
|
||||
def ch_maxPwdAge(self, val):
|
||||
self.ldb.set_maxPwdAge(val)
|
||||
|
||||
def ch_minPwdLength(self, val):
|
||||
self.ldb.set_minPwdLength(val)
|
||||
|
||||
def ch_pwdProperties(self, val):
|
||||
self.ldb.set_pwdProperties(val)
|
||||
|
||||
def explicit(self):
|
||||
return self.val
|
||||
|
||||
def nttime2unix(self):
|
||||
seconds = 60
|
||||
minutes = 60
|
||||
hours = 24
|
||||
sam_add = 10000000
|
||||
val = (self.val)
|
||||
val = int(val)
|
||||
return str(-(val * seconds * minutes * hours * sam_add))
|
||||
|
||||
def mapper(self):
|
||||
'''ldap value : samba setter'''
|
||||
return { "minPwdAge" : (self.ch_minPwdAge, self.nttime2unix),
|
||||
"maxPwdAge" : (self.ch_maxPwdAge, self.nttime2unix),
|
||||
# Could be none, but I like the method assignment in update_samba
|
||||
"minPwdLength" : (self.ch_minPwdLength, self.explicit),
|
||||
"pwdProperties" : (self.ch_pwdProperties, self.explicit),
|
||||
|
||||
}
|
||||
|
||||
def update_samba(self):
|
||||
(upd_sam, value) = self.mapper().get(self.attribute)
|
||||
upd_sam(value()) # or val = value() then update(val)
|
||||
|
||||
|
||||
class gp_sec_ext(gp_ext):
|
||||
'''This class does the following two things:
|
||||
1) Identifies the GPO if it has a certain kind of filepath,
|
||||
2) Finally parses it.
|
||||
'''
|
||||
|
||||
count = 0
|
||||
|
||||
def __str__(self):
|
||||
return "Security GPO extension"
|
||||
|
||||
def list(self, rootpath):
|
||||
path = "%s%s" % (rootpath, "MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf")
|
||||
return path
|
||||
|
||||
def listmachpol(self, rootpath):
|
||||
path = "%s%s" % (rootpath, "Machine/Registry.pol")
|
||||
return path
|
||||
|
||||
def listuserpol(self, rootpath):
|
||||
path = "%s%s" % (rootpath, "User/Registry.pol")
|
||||
return path
|
||||
|
||||
def populate_inf(self):
|
||||
return {"System Access": {"MinimumPasswordAge": ("minPwdAge", inf_to_ldb),
|
||||
"MaximumPasswordAge": ("maxPwdAge", inf_to_ldb),
|
||||
"MinimumPasswordLength": ("minPwdLength", inf_to_ldb),
|
||||
"PasswordComplexity": ("pwdProperties", inf_to_ldb),
|
||||
}
|
||||
}
|
||||
|
||||
def read_inf(self, path, conn, attr_log):
|
||||
ret = False
|
||||
inftable = self.populate_inf()
|
||||
|
||||
policy = conn.loadfile(path).decode('utf-16')
|
||||
current_section = None
|
||||
LOG = open(attr_log, "a")
|
||||
LOG.write(str(path.split('/')[2]) + '\n')
|
||||
|
||||
# So here we would declare a boolean,
|
||||
# that would get changed to TRUE.
|
||||
#
|
||||
# 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'))
|
||||
|
||||
else:
|
||||
# We must be in a section
|
||||
if not current_section:
|
||||
continue
|
||||
(key, value) = line.split("=")
|
||||
key = key.strip()
|
||||
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()
|
||||
return ret
|
||||
|
||||
def parse(self, afile, ldb, conn, attr_log):
|
||||
self.ldb = ldb
|
||||
self.dn = ldb.get_default_basedn()
|
||||
|
||||
# Fixing the bug where only some Linux Boxes capitalize MACHINE
|
||||
if afile.endswith('inf'):
|
||||
try:
|
||||
blist = afile.split('/')
|
||||
idx = afile.lower().split('/').index('machine')
|
||||
for case in [blist[idx].upper(), blist[idx].capitalize(), blist[idx].lower()]:
|
||||
bfile = '/'.join(blist[:idx]) + '/' + case + '/' + '/'.join(blist[idx+1:])
|
||||
try:
|
||||
return self.read_inf(bfile, conn, attr_log)
|
||||
except NTSTATUSError:
|
||||
continue
|
||||
except ValueError:
|
||||
try:
|
||||
return self.read_inf(afile, conn, attr_log)
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def scan_log(sysvol_path):
|
||||
a = open(sysvol_path, "r")
|
||||
data = {}
|
||||
for line in a.readlines():
|
||||
line = line.strip()
|
||||
(guid, version) = line.split(" ")
|
||||
data[guid] = int(version)
|
||||
return data
|
||||
|
||||
|
||||
def Reset_Defaults(test_ldb):
|
||||
test_ldb.set_minPwdAge(str(-25920000000000))
|
||||
test_ldb.set_maxPwdAge(str(-38016000000000))
|
||||
test_ldb.set_minPwdLength(str(7))
|
||||
test_ldb.set_pwdProperties(str(1))
|
||||
|
||||
|
||||
def check_deleted(guid_list, backloggpo):
|
||||
if backloggpo is None:
|
||||
return False
|
||||
for guid in backloggpo:
|
||||
if guid not in guid_list:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# The hierarchy is as per MS http://msdn.microsoft.com/en-us/library/windows/desktop/aa374155%28v=vs.85%29.aspx
|
||||
#
|
||||
# It does not care about local GPO, because GPO and snap-ins are not made in Linux yet.
|
||||
# It follows the linking order and children GPO are last written format.
|
||||
#
|
||||
# Also, couple further testing with call scripts entitled informant and informant2.
|
||||
# They explicitly show the returned hierarchically sorted list.
|
||||
|
||||
|
||||
def container_indexes(GUID_LIST):
|
||||
'''So the original list will need to be seperated into containers.
|
||||
Returns indexed list of when the container changes after hierarchy
|
||||
'''
|
||||
count = 0
|
||||
container_indexes = []
|
||||
while count < (len(GUID_LIST)-1):
|
||||
if GUID_LIST[count][2] != GUID_LIST[count+1][2]:
|
||||
container_indexes.append(count+1)
|
||||
count += 1
|
||||
container_indexes.append(len(GUID_LIST))
|
||||
return container_indexes
|
||||
|
||||
|
||||
def sort_linked(SAMDB, guid_list, start, end):
|
||||
'''So GPO in same level need to have link level.
|
||||
This takes a container and sorts it.
|
||||
|
||||
TODO: Small small problem, it is backwards
|
||||
'''
|
||||
containers = gpo_user.get_gpo_containers(SAMDB, guid_list[start][0])
|
||||
for right_container in containers:
|
||||
if right_container.get('dn') == guid_list[start][2]:
|
||||
break
|
||||
gplink = str(right_container.get('gPLink'))
|
||||
gplink_split = gplink.split('[')
|
||||
linked_order = []
|
||||
ret_list = []
|
||||
for ldap_guid in gplink_split:
|
||||
linked_order.append(str(ldap_guid[10:48]))
|
||||
count = len(linked_order) - 1
|
||||
while count > 0:
|
||||
ret_list.append([linked_order[count], guid_list[start][1], guid_list[start][2]])
|
||||
count -= 1
|
||||
return ret_list
|
||||
|
||||
|
||||
def establish_hierarchy(SamDB, GUID_LIST, DC_OU, global_dn):
|
||||
'''Takes a list of GUID from gpo, and sorts them based on OU, and realm.
|
||||
See http://msdn.microsoft.com/en-us/library/windows/desktop/aa374155%28v=vs.85%29.aspx
|
||||
'''
|
||||
final_list = []
|
||||
count_unapplied_GPO = 0
|
||||
for GUID in GUID_LIST:
|
||||
|
||||
container_iteration = 0
|
||||
# Assume first it is not applied
|
||||
applied = False
|
||||
# Realm only written on last call, if the GPO is linked to multiple places
|
||||
gpo_realm = False
|
||||
|
||||
# A very important call. This gets all of the linked information.
|
||||
GPO_CONTAINERS = gpo_user.get_gpo_containers(SamDB, GUID)
|
||||
for GPO_CONTAINER in GPO_CONTAINERS:
|
||||
|
||||
container_iteration += 1
|
||||
|
||||
if DC_OU == str(GPO_CONTAINER.get('dn')):
|
||||
applied = True
|
||||
insert_gpo = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
|
||||
final_list.append(insert_gpo)
|
||||
break
|
||||
|
||||
if global_dn == str(GPO_CONTAINER.get('dn')) and (len(GPO_CONTAINERS) == 1):
|
||||
gpo_realm = True
|
||||
applied = True
|
||||
|
||||
|
||||
if global_dn == str(GPO_CONTAINER.get('dn')) and (len(GPO_CONTAINERS) > 1):
|
||||
gpo_realm = True
|
||||
applied = True
|
||||
|
||||
|
||||
if container_iteration == len(GPO_CONTAINERS):
|
||||
if gpo_realm == False:
|
||||
insert_dud = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
|
||||
final_list.insert(0, insert_dud)
|
||||
count_unapplied_GPO += 1
|
||||
else:
|
||||
REALM_GPO = [GUID, applied, str(GPO_CONTAINER.get('dn'))]
|
||||
final_list.insert(count_unapplied_GPO, REALM_GPO)
|
||||
|
||||
# After GPO are sorted into containers, let's sort the containers themselves.
|
||||
# But first we can get the GPO that we don't care about, out of the way.
|
||||
indexed_places = container_indexes(final_list)
|
||||
count = 0
|
||||
unapplied_gpo = []
|
||||
# Sorted by container
|
||||
sorted_gpo_list = []
|
||||
|
||||
# Unapplied GPO live at start of list, append them to final list
|
||||
while final_list[0][1] == False:
|
||||
unapplied_gpo.append(final_list[count])
|
||||
count += 1
|
||||
count = 0
|
||||
sorted_gpo_list += unapplied_gpo
|
||||
|
||||
# A single container call gets the linked order for all GPO in container.
|
||||
# So we need one call per container - > index of the Original list
|
||||
indexed_places.insert(0, 0)
|
||||
while count < (len(indexed_places)-1):
|
||||
sorted_gpo_list += (sort_linked(SamDB, final_list, indexed_places[count], indexed_places[count+1]))
|
||||
count += 1
|
||||
return sorted_gpo_list
|
@ -831,6 +831,24 @@ accountExpires: %u
|
||||
else:
|
||||
return res[0]["minPwdAge"][0]
|
||||
|
||||
def set_maxPwdAge(self, value):
|
||||
m = ldb.Message()
|
||||
m.dn = ldb.Dn(self, self.domain_dn())
|
||||
m["maxPwdAge"] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, "maxPwdAge")
|
||||
self.modify(m)
|
||||
|
||||
|
||||
def get_maxPwdAge(self):
|
||||
res = self.search(self.domain_dn(), scope=ldb.SCOPE_BASE, attrs=["maxPwdAge"])
|
||||
if len(res) == 0:
|
||||
return None
|
||||
elif not "maxPwdAge" in res[0]:
|
||||
return None
|
||||
else:
|
||||
return res[0]["maxPwdAge"][0]
|
||||
|
||||
|
||||
|
||||
def set_minPwdLength(self, value):
|
||||
m = ldb.Message()
|
||||
m.dn = ldb.Dn(self, self.domain_dn())
|
||||
|
235
source4/scripting/bin/samba_gpoupdate
Executable file
235
source4/scripting/bin/samba_gpoupdate
Executable file
@ -0,0 +1,235 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright Luke Morrison <luc785@.hotmail.com> July 2013
|
||||
# Co-Edited by Matthieu Pattou July 2013 from original August 2013
|
||||
# Edited by Garming Sam Feb. 2014
|
||||
# Edited by Luke Morrison April 2014
|
||||
|
||||
# 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/>.
|
||||
|
||||
'''This script reads a log file of previous GPO, gets all GPO from sysvol
|
||||
and sorts them by container. Then, it applies the ones that haven't been
|
||||
applied, have changed, or is in the right container'''
|
||||
|
||||
import os
|
||||
import fcntl
|
||||
import sys
|
||||
import tempfile
|
||||
import subprocess
|
||||
|
||||
sys.path.insert(0, "bin/python")
|
||||
|
||||
import samba
|
||||
import optparse
|
||||
from samba import getopt as options
|
||||
from samba.gpclass import *
|
||||
from samba.net import Net
|
||||
from samba.dcerpc import nbt
|
||||
from samba import smb
|
||||
|
||||
|
||||
# Finds all GPO Files ending in inf
|
||||
def gp_path_list(path):
|
||||
|
||||
GPO_LIST = []
|
||||
for ext in gp_extensions:
|
||||
GPO_LIST.append((ext, ext.list(path)))
|
||||
return GPO_LIST
|
||||
|
||||
|
||||
def gpo_parser(GPO_LIST, ldb, conn, attr_log):
|
||||
'''The API method to parse the GPO
|
||||
:param GPO_LIST:
|
||||
:param ldb: Live instance of an LDB object AKA Samba
|
||||
:param conn: Live instance of a CIFS connection
|
||||
:param attr_log: backlog path for GPO and attribute to be written
|
||||
no return except a newly updated Samba
|
||||
'''
|
||||
|
||||
ret = False
|
||||
for entry in GPO_LIST:
|
||||
(ext, thefile) = entry
|
||||
if ret == False:
|
||||
ret = ext.parse(thefile, ldb, conn, attr_log)
|
||||
else:
|
||||
temp = ext.parse(thefile, ldb, conn, attr_log)
|
||||
return ret
|
||||
|
||||
|
||||
class GPOServiceSetup:
|
||||
def __init__(self):
|
||||
"""Initialize all components necessary to return instances of
|
||||
a Samba lp context (smb.conf) and Samba LDB context
|
||||
"""
|
||||
|
||||
self.parser = optparse.OptionParser("samba_gpoupdate [options]")
|
||||
self.sambaopts = options.SambaOptions(self.parser)
|
||||
self.credopts = None
|
||||
self.opts = None
|
||||
self.args = None
|
||||
self.lp = None
|
||||
self.smbconf = None
|
||||
self.creds = None
|
||||
self.url = None
|
||||
|
||||
# Setters or Initializers
|
||||
def init_parser(self):
|
||||
'''Get the command line options'''
|
||||
self.parser.add_option_group(self.sambaopts)
|
||||
self.parser.add_option_group(options.VersionOptions(self.parser))
|
||||
self.init_credopts()
|
||||
self.parser.add_option("-H", dest="url", help="URL for the samdb")
|
||||
self.parser.add_option_group(self.credopts)
|
||||
|
||||
def init_argsopts(self):
|
||||
'''Set the options and the arguments'''
|
||||
(opts, args) = self.parser.parse_args()
|
||||
|
||||
self.opts = opts
|
||||
self.args = args
|
||||
|
||||
def init_credopts(self):
|
||||
'''Set Credential operations'''
|
||||
self.credopts = options.CredentialsOptions(self.parser)
|
||||
|
||||
def init_lp(self):
|
||||
'''Set the loadparm context'''
|
||||
self.lp = self.sambaopts.get_loadparm()
|
||||
self.smbconf = self.lp.configfile
|
||||
if (not self.opts.url):
|
||||
self.url = self.lp.samdb_url()
|
||||
else:
|
||||
self.url = self.opts.url
|
||||
|
||||
def init_session(self):
|
||||
'''Initialize the session'''
|
||||
self.creds = self.credopts.get_credentials(self.lp,
|
||||
fallback_machine=True)
|
||||
self.session = system_session()
|
||||
|
||||
def InitializeService(self):
|
||||
'''Inializer for the thread'''
|
||||
self.init_parser()
|
||||
self.init_argsopts()
|
||||
self.init_lp()
|
||||
self.init_session()
|
||||
|
||||
# Getters
|
||||
def Get_LDB(self):
|
||||
'''Return a live instance of Samba'''
|
||||
SambaDB = SamDB(self.url, session_info=self.session,
|
||||
credentials=self.creds, lp=self.lp)
|
||||
return SambaDB
|
||||
|
||||
def Get_lp_Content(self):
|
||||
'''Return an instance of a local lp context'''
|
||||
return self.lp
|
||||
|
||||
def Get_Creds(self):
|
||||
'''Return an instance of a local creds'''
|
||||
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()
|
||||
|
||||
# Get the Samba Instance
|
||||
test_ldb = GPOService.Get_LDB()
|
||||
|
||||
# Get The lp context
|
||||
lp = GPOService.Get_lp_Content()
|
||||
|
||||
# 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')
|
||||
attr_log = '%s/%s' % (lp.get("path", "sysvol"), 'attrlog.txt')
|
||||
BackLoggedGPO = GetBackLog(sys_log)
|
||||
|
||||
|
||||
BackLog = open(sys_log, "w")
|
||||
|
||||
|
||||
# We need to know writable DC to setup SMB connection
|
||||
net = Net(creds=creds, lp=lp)
|
||||
cldap_ret = net.finddc(domain=lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP |
|
||||
nbt.NBT_SERVER_DS))
|
||||
dc_hostname = cldap_ret.pdc_dns_name
|
||||
|
||||
try:
|
||||
conn = smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds)
|
||||
except Exception, e:
|
||||
raise Exception("Error connecting to '%s' using SMB" % dc_hostname, e)
|
||||
|
||||
# Get the dn of the domain, and the dn of readable/writable DC
|
||||
global_dn = test_ldb.domain_dn()
|
||||
DC_OU = "OU=Domain Controllers" + ',' + global_dn
|
||||
|
||||
# Set up a List of the GUID for all GPO's
|
||||
guid_list = [x['name'] for x in conn.list('%s/Policies' % lp.get("realm").lower())]
|
||||
SYSV_PATH = '%s/%s/%s' % (lp.get("path", "sysvol"), lp.get("realm"), 'Policies')
|
||||
|
||||
hierarchy_gpos = establish_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
|
||||
change_backlog = False
|
||||
|
||||
# Take a local list of all current GPO list and run it against previous GPO's
|
||||
# to see if something has changed. If so reset default and re-apply GPO.
|
||||
Applicable_GPO = []
|
||||
for i in hierarchy_gpos:
|
||||
Applicable_GPO += i
|
||||
|
||||
# Flag gets set when
|
||||
GPO_Changed = False
|
||||
GPO_Deleted = check_deleted(Applicable_GPO, BackLoggedGPO)
|
||||
if (GPO_Deleted):
|
||||
# Null the backlog
|
||||
BackLoggedGPO = {}
|
||||
# Reset defaults then overwrite them
|
||||
Reset_Defaults(test_ldb)
|
||||
GPO_Changed = False
|
||||
|
||||
for guid_eval in hierarchy_gpos:
|
||||
guid = guid_eval[0]
|
||||
gp_extensions = [gp_sec_ext()]
|
||||
local_path = '%s/Policies' % lp.get("realm").lower() + '/' + guid + '/'
|
||||
version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
|
||||
gpolist = gp_path_list(local_path)
|
||||
if(version != BackLoggedGPO.get(guid)):
|
||||
GPO_Changed = True
|
||||
# If the GPO has a dn that is applicable to Samba
|
||||
if guid_eval[1]:
|
||||
# If it has a GPO file that could apply to Samba
|
||||
if gpolist[0][1]:
|
||||
# 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)
|
||||
|
||||
BackLog.write('%s %i\n' % (guid, version))
|
Loading…
Reference in New Issue
Block a user