gpo: Add the winbind call to gpupdate
[kai/samba-autobuild/.git] / source4 / scripting / bin / samba_gpoupdate
1 #!/usr/bin/env python
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
7
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.
12 #
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.
17 #
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/>.
20
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'''
24
25 import os
26 import sys
27
28 sys.path.insert(0, "bin/python")
29
30 import optparse
31 from samba import getopt as options
32 from samba.auth import system_session
33 try:
34     from samba.samdb import SamDB
35 except:
36     SamDB = None
37 from samba.gpclass import *
38 from samba.net import Net
39 from samba.dcerpc import nbt
40 from samba import smb
41 import samba.gpo as gpo
42 import logging
43 import chardet
44
45 ''' Fetch the hostname of a writable DC '''
46 def get_dc_hostname(creds, lp):
47     net = Net(creds=creds, lp=lp)
48     cldap_ret = net.finddc(domain=lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP |
49         nbt.NBT_SERVER_DS))
50     return cldap_ret.pdc_dns_name
51
52 ''' Fetch a list of GUIDs for applicable GPOs '''
53 def get_gpo_list(dc_hostname, creds, lp):
54     gpos = []
55     ads = gpo.ADS_STRUCT(dc_hostname, lp, creds)
56     if ads.connect():
57         gpos = ads.get_gpo_list(creds.get_username())
58     return gpos
59
60 def apply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
61     gp_db = store.get_gplog(creds.get_username())
62     dc_hostname = get_dc_hostname(creds, lp)
63     try:
64         conn =  smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds)
65     except:
66         logger.error('Error connecting to \'%s\' using SMB' % dc_hostname)
67         raise
68     gpos = get_gpo_list(dc_hostname, creds, lp)
69
70     for gpo_obj in gpos:
71         guid = gpo_obj.name
72         if guid == 'Local Policy':
73             continue
74         path = os.path.join(lp.get('realm').lower(), 'Policies', guid)
75         local_path = os.path.join(lp.get("path", "sysvol"), path)
76         version = int(gpo.gpo_get_sysvol_gpt_version(local_path)[1])
77         if version != store.get_int(guid):
78             logger.info('GPO %s has changed' % guid)
79             gp_db.state(GPOSTATE.APPLY)
80         else:
81             gp_db.state(GPOSTATE.ENFORCE)
82         gp_db.set_guid(guid)
83         store.start()
84         for ext in gp_extensions:
85             try:
86                 ext.parse(ext.list(path), test_ldb, conn, gp_db, lp)
87             except Exception as e:
88                 logger.error('Failed to parse gpo %s for extension %s' % \
89                     (guid, str(ext)))
90                 logger.error('Message was: ' + str(e))
91                 store.cancel()
92                 continue
93         store.store(guid, '%i' % version)
94         store.commit()
95
96 def unapply_log(gp_db):
97     while True:
98         item = gp_db.apply_log_pop()
99         if item:
100             yield item
101         else:
102             break
103
104 def unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions):
105     gp_db = store.get_gplog(creds.get_username())
106     gp_db.state(GPOSTATE.UNAPPLY)
107     for gpo_guid in unapply_log(gp_db):
108         gp_db.set_guid(gpo_guid)
109         unapply_attributes = gp_db.list(gp_extensions)
110         for attr in unapply_attributes:
111             attr_obj = attr[-1](logger, test_ldb, gp_db, lp, attr[0], attr[1])
112             attr_obj.mapper()[attr[0]][0](attr[1]) # Set the old value
113             gp_db.delete(str(attr_obj), attr[0])
114         gp_db.commit()
115
116 if __name__ == "__main__":
117     parser = optparse.OptionParser('samba_gpoupdate [options]')
118     sambaopts = options.SambaOptions(parser)
119
120     # Get the command line options
121     parser.add_option_group(sambaopts)
122     parser.add_option_group(options.VersionOptions(parser))
123     credopts = options.CredentialsOptions(parser)
124     parser.add_option('-H', '--url', dest='url', help='URL for the samdb')
125     parser.add_option('-X', '--unapply', help='Unapply Group Policy',
126                       action='store_true')
127     parser.add_option('-M', '--machine', help='Apply machine policy',
128                       action='store_true', default=False)
129     parser.add_option_group(credopts)
130
131     # Set the options and the arguments
132     (opts, args) = parser.parse_args()
133
134     # Set the loadparm context
135     lp = sambaopts.get_loadparm()
136     if not opts.url:
137         url = lp.samdb_url()
138     else:
139         url = opts.url
140
141     # Initialize the session
142     creds = credopts.get_credentials(lp, fallback_machine=True)
143     session = system_session()
144
145     # Set up logging
146     logger = logging.getLogger('samba_gpoupdate')
147     logger.addHandler(logging.StreamHandler(sys.stdout))
148     logger.setLevel(logging.CRITICAL)
149     log_level = lp.log_level()
150     if log_level == 1:
151         logger.setLevel(logging.ERROR)
152     elif log_level == 2:
153         logger.setLevel(logging.WARNING)
154     elif log_level == 3:
155         logger.setLevel(logging.INFO)
156     elif log_level >= 4:
157         logger.setLevel(logging.DEBUG)
158
159     cache_dir = lp.get('cache directory')
160     store = GPOStorage(os.path.join(cache_dir, 'gpo.tdb'))
161
162     gp_extensions = []
163     if opts.machine:
164         if lp.get('server role') == 'active directory domain controller':
165             gp_extensions.append(gp_sec_ext(logger))
166     else:
167         pass # User extensions
168
169     # Get a live instance of Samba
170     if SamDB:
171         test_ldb = SamDB(url, session_info=session, credentials=creds, lp=lp)
172     else:
173         test_ldb = None
174
175     if not opts.unapply:
176         apply_gp(lp, creds, test_ldb, logger, store, gp_extensions)
177     else:
178         unapply_gp(lp, creds, test_ldb, logger, store, gp_extensions)
179