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'''
31 sys
.path
.insert(0, "bin/python")
35 from samba
import getopt
as options
36 from samba
.gpclass
import *
37 from samba
.net
import Net
38 from samba
.dcerpc
import nbt
43 # Finds all GPO Files ending in inf
44 def gp_path_list(path
):
47 for ext
in gp_extensions
:
48 GPO_LIST
.append((ext
, ext
.list(path
)))
52 def gpo_parser(GPO_LIST
, ldb
, conn
, attr_log
, lp
):
53 '''The API method to parse the GPO
55 :param ldb: Live instance of an LDB object AKA Samba
56 :param conn: Live instance of a CIFS connection
57 :param attr_log: backlog path for GPO and attribute to be written
58 no return except a newly updated Samba
62 for entry
in GPO_LIST
:
63 (ext
, thefile
) = entry
65 ret
= ext
.parse(thefile
, ldb
, conn
, attr_log
, lp
)
67 temp
= ext
.parse(thefile
, ldb
, conn
, attr_log
, lp
)
71 class GPOServiceSetup
:
73 """Initialize all components necessary to return instances of
74 a Samba lp context (smb.conf) and Samba LDB context
77 self
.parser
= optparse
.OptionParser("samba_gpoupdate [options]")
78 self
.sambaopts
= options
.SambaOptions(self
.parser
)
87 # Setters or Initializers
88 def init_parser(self
):
89 '''Get the command line options'''
90 self
.parser
.add_option_group(self
.sambaopts
)
91 self
.parser
.add_option_group(options
.VersionOptions(self
.parser
))
93 self
.parser
.add_option("-H", dest
="url", help="URL for the samdb")
94 self
.parser
.add_option_group(self
.credopts
)
96 def init_argsopts(self
):
97 '''Set the options and the arguments'''
98 (opts
, args
) = self
.parser
.parse_args()
103 def init_credopts(self
):
104 '''Set Credential operations'''
105 self
.credopts
= options
.CredentialsOptions(self
.parser
)
108 '''Set the loadparm context'''
109 self
.lp
= self
.sambaopts
.get_loadparm()
110 self
.smbconf
= self
.lp
.configfile
111 if (not self
.opts
.url
):
112 self
.url
= self
.lp
.samdb_url()
114 self
.url
= self
.opts
.url
116 def init_session(self
):
117 '''Initialize the session'''
118 self
.creds
= self
.credopts
.get_credentials(self
.lp
,
119 fallback_machine
=True)
120 self
.session
= system_session()
122 def InitializeService(self
):
123 '''Inializer for the thread'''
131 '''Return a live instance of Samba'''
132 SambaDB
= SamDB(self
.url
, session_info
=self
.session
,
133 credentials
=self
.creds
, lp
=self
.lp
)
136 def Get_lp_Content(self
):
137 '''Return an instance of a local lp context'''
141 '''Return an instance of a local creds'''
145 # Set up the GPO service
146 GPOService
= GPOServiceSetup()
147 GPOService
.InitializeService()
149 # Get the Samba Instance
150 test_ldb
= GPOService
.Get_LDB()
153 lp
= GPOService
.Get_lp_Content()
156 logger
= logging
.getLogger('samba_gpoupdate')
157 logger
.addHandler(logging
.StreamHandler(sys
.stdout
))
158 logger
.setLevel(logging
.CRITICAL
)
159 log_level
= lp
.log_level()
161 logger
.setLevel(logging
.ERROR
)
163 logger
.setLevel(logging
.WARNING
)
165 logger
.setLevel(logging
.INFO
)
167 logger
.setLevel(logging
.DEBUG
)
170 creds
= GPOService
.Get_Creds()
172 # Read the readable backLog into a hashmap
173 # then open writable backLog in same location
175 sys_log
= '%s/%s' % (lp
.get("path", "sysvol"), 'gpo.tdb')
176 attr_log
= '%s/%s' % (lp
.get("path", "sysvol"), 'attrlog.txt')
179 if os
.path
.isfile(sys_log
):
180 BackLog
= tdb
.open(sys_log
)
182 BackLog
= tdb
.Tdb(sys_log
, 0, tdb
.DEFAULT
, os
.O_CREAT|os
.O_RDWR
)
183 BackLoggedGPO
= scan_log(BackLog
)
186 # We need to know writable DC to setup SMB connection
187 net
= Net(creds
=creds
, lp
=lp
)
188 cldap_ret
= net
.finddc(domain
=lp
.get('realm'), flags
=(nbt
.NBT_SERVER_LDAP |
190 dc_hostname
= cldap_ret
.pdc_dns_name
193 conn
= smb
.SMB(dc_hostname
, 'sysvol', lp
=lp
, creds
=creds
)
195 raise Exception("Error connecting to '%s' using SMB" % dc_hostname
, e
)
197 # Get the dn of the domain, and the dn of readable/writable DC
198 global_dn
= test_ldb
.domain_dn()
199 DC_OU
= "OU=Domain Controllers" + ',' + global_dn
201 # Set up a List of the GUID for all GPO's
202 guid_list
= [x
['name'] for x
in conn
.list('%s/Policies' % lp
.get("realm").lower())]
203 SYSV_PATH
= '%s/%s/%s' % (lp
.get("path", "sysvol"), lp
.get("realm"), 'Policies')
205 hierarchy_gpos
= establish_hierarchy(test_ldb
, guid_list
, DC_OU
, global_dn
)
206 change_backlog
= False
208 # Take a local list of all current GPO list and run it against previous GPO's
209 # to see if something has changed. If so reset default and re-apply GPO.
211 for i
in hierarchy_gpos
:
216 GPO_Deleted
= check_deleted(Applicable_GPO
, BackLoggedGPO
)
220 # Reset defaults then overwrite them
221 Reset_Defaults(test_ldb
)
224 BackLog
.transaction_start()
225 for guid_eval
in hierarchy_gpos
:
227 gp_extensions
= [gp_sec_ext(logger
)]
228 local_path
= '%s/Policies' % lp
.get("realm").lower() + '/' + guid
+ '/'
229 version
= int(gpo
.gpo_get_sysvol_gpt_version(lp
.get("path", "sysvol") + '/' + local_path
)[1])
231 old_version
= int(BackLoggedGPO
.get(guid
))
234 gpolist
= gp_path_list(local_path
)
235 if version
!= old_version
:
237 # If the GPO has a dn that is applicable to Samba
239 # If it has a GPO file that could apply to Samba
241 # If it we have not read it before and is not empty
242 # Rewrite entire logfile here
243 if (version
!= 0) and GPO_Changed
== True:
244 logger
.info('GPO %s has changed' % guid
)
246 change_backlog
= gpo_parser(gpolist
, test_ldb
, conn
, attr_log
, lp
)
248 logger
.error('Failed to parse gpo %s' % guid
)
250 BackLog
.store(guid
, '%i' % version
)
251 BackLog
.transaction_commit()