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
6 # Edited by David Mulder May 2017
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 '''This script reads a log file of previous GPO, gets all GPO from sysvol
22 and sorts them by container. Then, it applies the ones that haven't been
23 applied, have changed, or is in the right container'''
28 sys.path.insert(0, "bin/python")
31 from samba import getopt as options
32 from samba.gpclass import *
33 from samba.net import Net
34 from samba.dcerpc import nbt
38 ''' Fetch the hostname of a writable DC '''
39 def get_dc_hostname():
40 net = Net(creds=creds, lp=lp)
41 cldap_ret = net.finddc(domain=lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP |
43 return cldap_ret.pdc_dns_name
45 ''' Fetch a list of GUIDs for applicable GPOs '''
46 def get_gpo_list(dc_hostname, creds, lp):
48 ads = gpo.ADS_STRUCT(dc_hostname, lp, creds)
50 gpos = ads.get_gpo_list(creds.get_username())
53 def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
54 gp_db = store.get_gplog(creds.get_username())
55 dc_hostname = get_dc_hostname()
57 conn = smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds)
59 logger.error('Error connecting to \'%s\' using SMB' % dc_hostname)
61 gpos = get_gpo_list(dc_hostname, creds, lp)
65 if guid == 'Local Policy':
67 local_path = os.path.join(lp.get('realm').lower(), 'Policies', guid)
68 version = int(gpo.gpo_get_sysvol_gpt_version(os.path.join(lp.get("path", "sysvol"), local_path))[1])
69 if version != store.get_int(guid):
70 logger.info('GPO %s has changed' % guid)
74 for ext in gp_extensions:
75 ext.parse(ext.list(local_path), test_ldb, conn, gp_db, lp)
77 logger.error('Failed to parse gpo %s' % guid)
80 store.store(guid, '%i' % version)
83 def unapply_log(gp_db):
85 item = gp_db.apply_log_pop()
91 def unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
92 gp_db = store.get_gplog(creds.get_username())
93 for gpo_guid in unapply_log(gp_db):
94 gp_db.set_guid(gpo_guid)
95 unapply_attributes = gp_db.list(gp_extensions)
96 for attr in unapply_attributes:
97 attr_obj = attr[-1](logger, test_ldb, gp_db, lp, attr[0], attr[1])
98 attr_obj.mapper()[attr[0]][0](attr[1]) # Set the old value
99 gp_db.delete(str(attr_obj), attr[0])
102 if __name__ == "__main__":
103 parser = optparse.OptionParser('samba_gpoupdate [options]')
104 sambaopts = options.SambaOptions(parser)
106 # Get the command line options
107 parser.add_option_group(sambaopts)
108 parser.add_option_group(options.VersionOptions(parser))
109 credopts = options.CredentialsOptions(parser)
110 parser.add_option('-H', '--url', dest='url', help='URL for the samdb')
111 parser.add_option('-X', '--unapply', help='Unapply Group Policy', action='store_true')
112 parser.add_option_group(credopts)
114 # Set the options and the arguments
115 (opts, args) = parser.parse_args()
117 # Set the loadparm context
118 lp = sambaopts.get_loadparm()
124 # Initialize the session
125 creds = credopts.get_credentials(lp, fallback_machine=True)
126 session = system_session()
129 logger = logging.getLogger('samba_gpoupdate')
130 logger.addHandler(logging.StreamHandler(sys.stdout))
131 logger.setLevel(logging.CRITICAL)
132 log_level = lp.log_level()
134 logger.setLevel(logging.ERROR)
136 logger.setLevel(logging.WARNING)
138 logger.setLevel(logging.INFO)
140 logger.setLevel(logging.DEBUG)
142 cache_dir = lp.get('cache directory')
143 store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
145 gp_extensions = [gp_sec_ext(logger)]
147 # Get a live instance of Samba
148 test_ldb = SamDB(url, session_info=session, credentials=creds, lp=lp)
151 apply_gp(lp, creds, test_ldb, logger, store, gp_extensions)
153 unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions)