gpoupdate: Rewrite samba_gpoupdate
[nivanova/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.gpclass import *
33 from samba.net import Net
34 from samba.dcerpc import nbt
35 from samba import smb
36 import logging
37
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 |
42         nbt.NBT_SERVER_DS))
43     return cldap_ret.pdc_dns_name
44
45 ''' Fetch a list of GUIDs for applicable GPOs '''
46 def get_gpo_list(dc_hostname, creds, lp):
47     gpos = []
48     ads = gpo.ADS_STRUCT(dc_hostname, lp, creds)
49     if ads.connect():
50         gpos = ads.get_gpo_list(creds.get_username())
51     return gpos
52
53 if __name__ == "__main__":
54     parser = optparse.OptionParser('samba_gpoupdate [options]')
55     sambaopts = options.SambaOptions(parser)
56
57     # Get the command line options
58     parser.add_option_group(sambaopts)
59     parser.add_option_group(options.VersionOptions(parser))
60     credopts = options.CredentialsOptions(parser)
61     parser.add_option('-H', '--url', dest='url', help='URL for the samdb')
62     parser.add_option_group(credopts)
63
64     # Set the options and the arguments
65     (opts, args) = parser.parse_args()
66
67     # Set the loadparm context
68     lp = sambaopts.get_loadparm()
69     if not opts.url:
70         url = lp.samdb_url()
71     else:
72         url = opts.url
73
74     # Initialize the session
75     creds = credopts.get_credentials(lp, fallback_machine=True)
76     session = system_session()
77
78     # Set up logging
79     logger = logging.getLogger('samba_gpoupdate')
80     logger.addHandler(logging.StreamHandler(sys.stdout))
81     logger.setLevel(logging.CRITICAL)
82     log_level = lp.log_level()
83     if log_level == 1:
84         logger.setLevel(logging.ERROR)
85     elif log_level == 2:
86         logger.setLevel(logging.WARNING)
87     elif log_level == 3:
88         logger.setLevel(logging.INFO)
89     elif log_level >= 4:
90         logger.setLevel(logging.DEBUG)
91
92     '''Return a live instance of Samba'''
93     test_ldb = SamDB(url, session_info=session, credentials=creds, lp=lp)
94
95     # Read the readable backLog into a hashmap
96     # then open writable backLog in same location
97     sysvol_log = os.path.join(lp.get('cache directory'), 'gpo.tdb')
98
99     backlog = Backlog(sysvol_log)
100
101     dc_hostname = get_dc_hostname()
102     try:
103         conn =  smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds)
104     except:
105         logger.error('Error connecting to \'%s\' using SMB' % dc_hostname)
106         raise
107     gpos = get_gpo_list(dc_hostname, creds, lp)
108
109     for gpo_obj in gpos:
110         guid = gpo_obj.name
111         if guid == 'Local Policy':
112             continue
113         gp_extensions = [gp_sec_ext(logger)]
114         local_path = os.path.join(lp.get('realm').lower(), 'Policies', guid)
115         version = int(gpo.gpo_get_sysvol_gpt_version(os.path.join(lp.get("path", "sysvol"), local_path))[1])
116         if version != backlog.version(guid):
117             logger.info('GPO %s has changed' % guid)
118             try:
119                 for ext in gp_extensions:
120                     ext.parse(ext.list(local_path), test_ldb, conn, lp)
121             except:
122                 logger.error('Failed to parse gpo %s' % guid)
123                 continue
124         backlog.store(guid, version)
125     backlog.commit()
126