2 # Copyright Luke Morrison <luc785@.hotmail.com> July 2013
3 # Co-Edited by Matthieu Pattou July 2013 from original August 2013
4 # Edited by Garming Sam Feb. 2014
5 # Edited by Luke Morrison April 2014
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 '''This script reads a log file of previous GPO, gets all GPO from sysvol
21 and sorts them by container. Then, it applies the ones that haven't been
22 applied, have changed, or is in the right container'''
30 sys.path.insert(0, "bin/python")
34 from samba import getopt as options
35 from samba.gpclass import *
36 from samba.net import Net
37 from samba.dcerpc import nbt
41 # Finds all GPO Files ending in inf
42 def gp_path_list(path):
45 for ext in gp_extensions:
46 GPO_LIST.append((ext, ext.list(path)))
50 def gpo_parser(GPO_LIST, ldb, conn, attr_log):
51 '''The API method to parse the GPO
53 :param ldb: Live instance of an LDB object AKA Samba
54 :param conn: Live instance of a CIFS connection
55 :param attr_log: backlog path for GPO and attribute to be written
56 no return except a newly updated Samba
60 for entry in GPO_LIST:
61 (ext, thefile) = entry
63 ret = ext.parse(thefile, ldb, conn, attr_log)
65 temp = ext.parse(thefile, ldb, conn, attr_log)
69 class GPOServiceSetup:
71 """Initialize all components necessary to return instances of
72 a Samba lp context (smb.conf) and Samba LDB context
75 self.parser = optparse.OptionParser("samba_gpoupdate [options]")
76 self.sambaopts = options.SambaOptions(self.parser)
85 # Setters or Initializers
86 def init_parser(self):
87 '''Get the command line options'''
88 self.parser.add_option_group(self.sambaopts)
89 self.parser.add_option_group(options.VersionOptions(self.parser))
91 self.parser.add_option("-H", dest="url", help="URL for the samdb")
92 self.parser.add_option_group(self.credopts)
94 def init_argsopts(self):
95 '''Set the options and the arguments'''
96 (opts, args) = self.parser.parse_args()
101 def init_credopts(self):
102 '''Set Credential operations'''
103 self.credopts = options.CredentialsOptions(self.parser)
106 '''Set the loadparm context'''
107 self.lp = self.sambaopts.get_loadparm()
108 self.smbconf = self.lp.configfile
109 if (not self.opts.url):
110 self.url = self.lp.samdb_url()
112 self.url = self.opts.url
114 def init_session(self):
115 '''Initialize the session'''
116 self.creds = self.credopts.get_credentials(self.lp,
117 fallback_machine=True)
118 self.session = system_session()
120 def InitializeService(self):
121 '''Inializer for the thread'''
129 '''Return a live instance of Samba'''
130 SambaDB = SamDB(self.url, session_info=self.session,
131 credentials=self.creds, lp=self.lp)
134 def Get_lp_Content(self):
135 '''Return an instance of a local lp context'''
139 '''Return an instance of a local creds'''
143 def GetBackLog(sys_log):
144 """Reads BackLog and makes thread aware of which GPO are unchanged or empty
145 :param String sys_log: path to backLog
146 :return Dictionary previous_scanned_version: {Unedited GPO: Version Number}
147 *NOTE on Version below
149 previous_scanned_version = {}
150 if os.path.isfile(sys_log):
151 previous_scanned_version = scan_log(sys_log)
152 return previous_scanned_version
156 # Set up the GPO service
157 GPOService = GPOServiceSetup()
158 GPOService.InitializeService()
160 # Get the Samba Instance
161 test_ldb = GPOService.Get_LDB()
164 lp = GPOService.Get_lp_Content()
167 creds = GPOService.Get_Creds()
169 # Read the readable backLog into a hashmap
170 # then open writable backLog in same location
172 sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
173 attr_log = '%s/%s' % (lp.get("path", "sysvol"), 'attrlog.txt')
174 BackLoggedGPO = GetBackLog(sys_log)
177 BackLog = open(sys_log, "w")
180 # We need to know writable DC to setup SMB connection
181 net = Net(creds=creds, lp=lp)
182 cldap_ret = net.finddc(domain=lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP |
184 dc_hostname = cldap_ret.pdc_dns_name
187 conn = smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds)
189 raise Exception("Error connecting to '%s' using SMB" % dc_hostname, e)
191 # Get the dn of the domain, and the dn of readable/writable DC
192 global_dn = test_ldb.domain_dn()
193 DC_OU = "OU=Domain Controllers" + ',' + global_dn
195 # Set up a List of the GUID for all GPO's
196 guid_list = [x['name'] for x in conn.list('%s/Policies' % lp.get("realm").lower())]
197 SYSV_PATH = '%s/%s/%s' % (lp.get("path", "sysvol"), lp.get("realm"), 'Policies')
199 hierarchy_gpos = establish_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
200 change_backlog = False
202 # Take a local list of all current GPO list and run it against previous GPO's
203 # to see if something has changed. If so reset default and re-apply GPO.
205 for i in hierarchy_gpos:
210 GPO_Deleted = check_deleted(Applicable_GPO, BackLoggedGPO)
214 # Reset defaults then overwrite them
215 Reset_Defaults(test_ldb)
218 for guid_eval in hierarchy_gpos:
220 gp_extensions = [gp_sec_ext()]
221 local_path = '%s/Policies' % lp.get("realm").lower() + '/' + guid + '/'
222 version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
223 gpolist = gp_path_list(local_path)
224 if(version != BackLoggedGPO.get(guid)):
226 # If the GPO has a dn that is applicable to Samba
228 # If it has a GPO file that could apply to Samba
230 # If it we have not read it before and is not empty
231 # Rewrite entire logfile here
232 if (version != 0) and GPO_Changed == True:
233 change_backlog = gpo_parser(gpolist, test_ldb, conn, attr_log)
235 BackLog.write('%s %i\n' % (guid, version))