1 # gp_sec_ext kdc gpo policy
2 # Copyright (C) Luke Morrison <luc785@.hotmail.com> 2013
3 # Copyright (C) David Mulder <dmulder@suse.com> 2018
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 from samba.gpclass import gp_inf_ext
20 from samba.auth import system_session
21 from samba.common import get_string
23 from ldb import LdbError
24 from samba.samdb import SamDB
28 def mins_to_hours(val):
29 return '%d' % (int(val) / 60)
31 def days_to_hours(val):
32 return '%d' % (int(val) * 24)
34 def days2rel_nttime(val):
40 return str(-(val * seconds * minutes * hours * sam_add))
42 class gp_krb_ext(gp_inf_ext):
43 apply_map = { 'MaxTicketAge': 'kdc:user_ticket_lifetime',
44 'MaxServiceAge': 'kdc:service_ticket_lifetime',
45 'MaxRenewAge': 'kdc:renewal_lifetime' }
46 def process_group_policy(self, deleted_gpo_list, changed_gpo_list):
47 if self.lp.get('server role') != 'active directory domain controller':
49 inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf'
50 for guid, settings in deleted_gpo_list:
51 self.gp_db.set_guid(guid)
52 for section in settings.keys():
53 if section == str(self):
54 for att, value in settings[section].items():
55 self.set_kdc_tdb(att, value)
56 self.gp_db.delete(section, att)
59 for gpo in changed_gpo_list:
61 self.gp_db.set_guid(gpo.name)
62 path = os.path.join(gpo.file_sys_path, inf_file)
63 inf_conf = self.parse(path)
66 for section in inf_conf.sections():
67 if section == str(self):
68 for key, value in inf_conf.items(section):
69 att = gp_krb_ext.apply_map[key]
70 value_func = self.mapper().get(att)
71 self.set_kdc_tdb(att, value_func(value))
74 def set_kdc_tdb(self, attribute, val):
75 old_val = self.gp_db.gpostore.get(attribute)
76 self.logger.info('%s was changed from %s to %s' % (attribute,
79 self.gp_db.gpostore.store(attribute, get_string(val))
80 self.gp_db.store(str(self), attribute, get_string(old_val) \
83 self.gp_db.gpostore.delete(attribute)
84 self.gp_db.delete(str(self), attribute)
87 return {'kdc:user_ticket_lifetime': lambda val: val,
88 'kdc:service_ticket_lifetime': mins_to_hours,
89 'kdc:renewal_lifetime': days_to_hours,
93 return 'Kerberos Policy'
97 if self.lp.get('server role') != 'active directory domain controller':
99 inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf'
100 if gpo.file_sys_path:
101 path = os.path.join(gpo.file_sys_path, inf_file)
102 inf_conf = self.parse(path)
105 for section in inf_conf.sections():
106 output[section] = {k: v for k, v in inf_conf.items(section) \
107 if gp_krb_ext.apply_map.get(k)}
111 class gp_access_ext(gp_inf_ext):
112 '''This class takes the .inf file parameter (essentially a GPO file mapped
113 to a GUID), hashmaps it to the Samba parameter, which then uses an ldb
114 object to update the parameter to Samba4. Not registry oriented whatsoever.
117 def __init__(self, *args):
118 super().__init__(*args)
120 self.ldb = SamDB(self.lp.samdb_url(),
121 session_info=system_session(),
122 credentials=self.creds,
124 except (NameError, LdbError):
125 raise Exception('Failed to load SamDB for assigning Group Policy')
127 apply_map = { 'MinimumPasswordAge': 'minPwdAge',
128 'MaximumPasswordAge': 'maxPwdAge',
129 'MinimumPasswordLength': 'minPwdLength',
130 'PasswordComplexity': 'pwdProperties' }
131 def process_group_policy(self, deleted_gpo_list, changed_gpo_list):
132 if self.lp.get('server role') != 'active directory domain controller':
134 inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf'
135 for guid, settings in deleted_gpo_list:
136 self.gp_db.set_guid(guid)
137 for section in settings.keys():
138 if section == str(self):
139 for att, value in settings[section].items():
140 update_samba, _ = self.mapper().get(att)
141 update_samba(att, value)
142 self.gp_db.delete(section, att)
145 for gpo in changed_gpo_list:
146 if gpo.file_sys_path:
147 self.gp_db.set_guid(gpo.name)
148 path = os.path.join(gpo.file_sys_path, inf_file)
149 inf_conf = self.parse(path)
152 for section in inf_conf.sections():
153 if section == str(self):
154 for key, value in inf_conf.items(section):
155 att = gp_access_ext.apply_map[key]
156 (update_samba, value_func) = self.mapper().get(att)
157 update_samba(att, value_func(value))
160 def ch_minPwdAge(self, attribute, val):
161 old_val = self.ldb.get_minPwdAge()
162 self.logger.info('KDC Minimum Password age was changed from %s to %s'
164 self.gp_db.store(str(self), attribute, str(old_val))
165 self.ldb.set_minPwdAge(val)
167 def ch_maxPwdAge(self, attribute, val):
168 old_val = self.ldb.get_maxPwdAge()
169 self.logger.info('KDC Maximum Password age was changed from %s to %s'
171 self.gp_db.store(str(self), attribute, str(old_val))
172 self.ldb.set_maxPwdAge(val)
174 def ch_minPwdLength(self, attribute, val):
175 old_val = self.ldb.get_minPwdLength()
177 'KDC Minimum Password length was changed from %s to %s'
179 self.gp_db.store(str(self), attribute, str(old_val))
180 self.ldb.set_minPwdLength(val)
182 def ch_pwdProperties(self, attribute, val):
183 old_val = self.ldb.get_pwdProperties()
184 self.logger.info('KDC Password Properties were changed from %s to %s'
186 self.gp_db.store(str(self), attribute, str(old_val))
187 self.ldb.set_pwdProperties(val)
190 '''ldap value : samba setter'''
191 return {"minPwdAge": (self.ch_minPwdAge, days2rel_nttime),
192 "maxPwdAge": (self.ch_maxPwdAge, days2rel_nttime),
193 # Could be none, but I like the method assignment in
195 "minPwdLength": (self.ch_minPwdLength, lambda val: val),
196 "pwdProperties": (self.ch_pwdProperties, lambda val: val),
201 return 'System Access'
205 if self.lp.get('server role') != 'active directory domain controller':
207 inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf'
208 if gpo.file_sys_path:
209 path = os.path.join(gpo.file_sys_path, inf_file)
210 inf_conf = self.parse(path)
213 for section in inf_conf.sections():
214 output[section] = {k: v for k, v in inf_conf.items(section) \
215 if gp_access_ext.apply_map.get(k)}