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)
71 gp_db.state(GPOSTATE.APPLY)
73 gp_db.state(GPOSTATE.ENFORCE)
77 for ext in gp_extensions:
78 ext.parse(ext.list(local_path), test_ldb, conn, gp_db, lp)
80 logger.error('Failed to parse gpo %s' % guid)
83 store.store(guid, '%i' % version)
86 def unapply_log(gp_db):
88 item = gp_db.apply_log_pop()
94 def unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
95 gp_db = store.get_gplog(creds.get_username())
96 gp_db.state(GPOSTATE.UNAPPLY)
97 for gpo_guid in unapply_log(gp_db):
98 gp_db.set_guid(gpo_guid)
99 unapply_attributes = gp_db.list(gp_extensions)
100 for attr in unapply_attributes:
101 attr_obj = attr[-1](logger, test_ldb, gp_db, lp, attr[0], attr[1])
102 attr_obj.mapper()[attr[0]][0](attr[1]) # Set the old value
103 gp_db.delete(str(attr_obj), attr[0])
106 if __name__ == "__main__":
107 parser = optparse.OptionParser('samba_gpoupdate [options]')
108 sambaopts = options.SambaOptions(parser)
110 # Get the command line options
111 parser.add_option_group(sambaopts)
112 parser.add_option_group(options.VersionOptions(parser))
113 credopts = options.CredentialsOptions(parser)
114 parser.add_option('-H', '--url', dest='url', help='URL for the samdb')
115 parser.add_option('-X', '--unapply', help='Unapply Group Policy', action='store_true')
116 parser.add_option_group(credopts)
118 # Set the options and the arguments
119 (opts, args) = parser.parse_args()
121 # Set the loadparm context
122 lp = sambaopts.get_loadparm()
128 # Initialize the session
129 creds = credopts.get_credentials(lp, fallback_machine=True)
130 session = system_session()
133 logger = logging.getLogger('samba_gpoupdate')
134 logger.addHandler(logging.StreamHandler(sys.stdout))
135 logger.setLevel(logging.CRITICAL)
136 log_level = lp.log_level()
138 logger.setLevel(logging.ERROR)
140 logger.setLevel(logging.WARNING)
142 logger.setLevel(logging.INFO)
144 logger.setLevel(logging.DEBUG)
146 cache_dir = lp.get('cache directory')
147 store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
149 gp_extensions = [gp_sec_ext(logger)]
151 # Get a live instance of Samba
152 test_ldb = SamDB(url, session_info=session, credentials=creds, lp=lp)
155 apply_gp(lp, creds, test_ldb, logger, store, gp_extensions)
157 unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions)