gpo: Initial commit for GPO work
[mdw/samba.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
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.
11 #
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.
16 #
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/>.
19
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'''
23
24 import os
25 import fcntl
26 import sys
27 import tempfile
28 import subprocess
29
30 sys.path.insert(0, "bin/python")
31
32 import samba
33 import optparse
34 from samba import getopt as options
35 from samba.gpclass import *
36 from samba.net import Net
37 from samba.dcerpc import nbt
38 from samba import smb
39
40
41 # Finds all GPO Files ending in inf
42 def gp_path_list(path):
43
44     GPO_LIST = []
45     for ext in gp_extensions:
46         GPO_LIST.append((ext, ext.list(path)))
47     return GPO_LIST
48
49
50 def gpo_parser(GPO_LIST, ldb, conn, attr_log):
51     '''The API method to parse the GPO
52     :param GPO_LIST:
53     :param ldb: Live instance of an LDB object AKA Samba
54     :param conn: Live instance of a CIFS connection
55     :param attr_log: backlog path for GPO and attribute to be written
56     no return except a newly updated Samba
57     '''
58
59     ret = False
60     for entry in GPO_LIST:
61         (ext, thefile) = entry
62         if ret == False:
63             ret = ext.parse(thefile, ldb, conn, attr_log)
64         else:
65             temp = ext.parse(thefile, ldb, conn, attr_log)
66     return ret
67
68
69 class GPOServiceSetup:
70     def __init__(self):
71         """Initialize all components necessary to return instances of
72         a Samba lp context (smb.conf) and Samba LDB context
73         """
74
75         self.parser = optparse.OptionParser("samba_gpoupdate [options]")
76         self.sambaopts = options.SambaOptions(self.parser)
77         self.credopts = None
78         self.opts = None
79         self.args = None
80         self.lp = None
81         self.smbconf = None
82         self.creds = None
83         self.url = None
84
85     # Setters or Initializers
86     def init_parser(self):
87         '''Get the command line options'''
88         self.parser.add_option_group(self.sambaopts)
89         self.parser.add_option_group(options.VersionOptions(self.parser))
90         self.init_credopts()
91         self.parser.add_option("-H", dest="url", help="URL for the samdb")
92         self.parser.add_option_group(self.credopts)
93
94     def init_argsopts(self):
95         '''Set the options and the arguments'''
96         (opts, args) = self.parser.parse_args()
97
98         self.opts = opts
99         self.args = args
100
101     def init_credopts(self):
102         '''Set Credential operations'''
103         self.credopts = options.CredentialsOptions(self.parser)
104
105     def init_lp(self):
106         '''Set the loadparm context'''
107         self.lp = self.sambaopts.get_loadparm()
108         self.smbconf = self.lp.configfile
109         if (not self.opts.url):
110             self.url = self.lp.samdb_url()
111         else:
112             self.url = self.opts.url
113
114     def init_session(self):
115         '''Initialize the session'''
116         self.creds = self.credopts.get_credentials(self.lp,
117             fallback_machine=True)
118         self.session = system_session()
119
120     def InitializeService(self):
121         '''Inializer for the thread'''
122         self.init_parser()
123         self.init_argsopts()
124         self.init_lp()
125         self.init_session()
126
127     # Getters
128     def Get_LDB(self):
129         '''Return a live instance of Samba'''
130         SambaDB = SamDB(self.url, session_info=self.session,
131             credentials=self.creds, lp=self.lp)
132         return SambaDB
133
134     def Get_lp_Content(self):
135         '''Return an instance of a local lp context'''
136         return self.lp
137
138     def Get_Creds(self):
139         '''Return an instance of a local creds'''
140         return self.creds
141
142
143 def GetBackLog(sys_log):
144     """Reads BackLog and makes thread aware of which GPO are unchanged or empty
145     :param String sys_log: path to backLog
146     :return Dictionary previous_scanned_version: {Unedited GPO: Version Number}
147     *NOTE on Version below
148     """
149     previous_scanned_version = {}
150     if os.path.isfile(sys_log):
151         previous_scanned_version = scan_log(sys_log)
152         return previous_scanned_version
153     else:
154         return None
155
156 # Set up the GPO service
157 GPOService = GPOServiceSetup()
158 GPOService.InitializeService()
159
160 # Get the Samba Instance
161 test_ldb = GPOService.Get_LDB()
162
163 # Get The lp context
164 lp = GPOService.Get_lp_Content()
165
166 # Get the CREDS
167 creds = GPOService.Get_Creds()
168
169 # Read the readable backLog into a hashmap
170 # then open writable backLog in same location
171 BackLoggedGPO = None
172 sys_log = '%s/%s' % (lp.get("path", "sysvol"), 'syslog.txt')
173 attr_log = '%s/%s' % (lp.get("path", "sysvol"), 'attrlog.txt')
174 BackLoggedGPO = GetBackLog(sys_log)
175
176
177 BackLog = open(sys_log, "w")
178
179
180 # We need to know writable DC to setup SMB connection
181 net = Net(creds=creds, lp=lp)
182 cldap_ret = net.finddc(domain=lp.get('realm'), flags=(nbt.NBT_SERVER_LDAP |
183     nbt.NBT_SERVER_DS))
184 dc_hostname = cldap_ret.pdc_dns_name
185
186 try:
187     conn = smb.SMB(dc_hostname, 'sysvol', lp=lp, creds=creds)
188 except Exception, e:
189     raise Exception("Error connecting to '%s' using SMB" % dc_hostname, e)
190
191 # Get the dn of the domain, and the dn of readable/writable DC
192 global_dn = test_ldb.domain_dn()
193 DC_OU = "OU=Domain Controllers" + ',' + global_dn
194
195 # Set up a List of the GUID for all GPO's
196 guid_list = [x['name'] for x in conn.list('%s/Policies' % lp.get("realm").lower())]
197 SYSV_PATH = '%s/%s/%s' % (lp.get("path", "sysvol"), lp.get("realm"), 'Policies')
198
199 hierarchy_gpos = establish_hierarchy(test_ldb, guid_list, DC_OU, global_dn)
200 change_backlog = False
201
202 # Take a local list of all current GPO list and run it against previous GPO's
203 # to see if something has changed. If so reset default and re-apply GPO.
204 Applicable_GPO = []
205 for i in hierarchy_gpos:
206     Applicable_GPO += i
207
208 # Flag gets set when
209 GPO_Changed = False
210 GPO_Deleted = check_deleted(Applicable_GPO, BackLoggedGPO)
211 if (GPO_Deleted):
212     # Null the backlog
213     BackLoggedGPO = {}
214     # Reset defaults then overwrite them
215     Reset_Defaults(test_ldb)
216     GPO_Changed = False
217
218 for guid_eval in hierarchy_gpos:
219     guid = guid_eval[0]
220     gp_extensions = [gp_sec_ext()]
221     local_path = '%s/Policies' % lp.get("realm").lower() + '/' + guid + '/'
222     version = gpo.gpo_get_sysvol_gpt_version(lp.get("path", "sysvol") + '/' + local_path)[1]
223     gpolist = gp_path_list(local_path)
224     if(version != BackLoggedGPO.get(guid)):
225         GPO_Changed = True
226     # If the GPO has a dn that is applicable to Samba
227     if guid_eval[1]:
228         # If it has a GPO file that could apply to Samba
229         if gpolist[0][1]:
230             # If it we have not read it before and is not empty
231             # Rewrite entire logfile here
232             if  (version != 0) and GPO_Changed == True:
233                 change_backlog = gpo_parser(gpolist, test_ldb, conn, attr_log)
234
235     BackLog.write('%s %i\n' % (guid, version))