mdb_util: Better error message if lmdb-utils not installed
[amitay/samba.git] / python / samba / gp_sec_ext.py
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
4 #
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.
9 #
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.
14 #
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/>.
17
18 import os.path
19 from samba.gpclass import gp_ext_setter, gp_inf_ext
20 from samba.auth import system_session
21 try:
22     from ldb import LdbError
23     from samba.samdb import SamDB
24 except ImportError:
25     pass
26
27
28 class inf_to_kdc_tdb(gp_ext_setter):
29     def mins_to_hours(self):
30         return '%d' % (int(self.val) / 60)
31
32     def days_to_hours(self):
33         return '%d' % (int(self.val) * 24)
34
35     def set_kdc_tdb(self, val):
36         old_val = self.gp_db.gpostore.get(self.attribute)
37         self.logger.info('%s was changed from %s to %s' % (self.attribute,
38                                                            old_val, val))
39         if val is not None:
40             self.gp_db.gpostore.store(self.attribute, val)
41             self.gp_db.store(str(self), self.attribute, old_val)
42         else:
43             self.gp_db.gpostore.delete(self.attribute)
44             self.gp_db.delete(str(self), self.attribute)
45
46     def mapper(self):
47         return {'kdc:user_ticket_lifetime': (self.set_kdc_tdb, self.explicit),
48                 'kdc:service_ticket_lifetime': (self.set_kdc_tdb,
49                                                 self.mins_to_hours),
50                 'kdc:renewal_lifetime': (self.set_kdc_tdb,
51                                          self.days_to_hours),
52                 }
53
54     def __str__(self):
55         return 'Kerberos Policy'
56
57
58 class inf_to_ldb(gp_ext_setter):
59     '''This class takes the .inf file parameter (essentially a GPO file mapped
60     to a GUID), hashmaps it to the Samba parameter, which then uses an ldb
61     object to update the parameter to Samba4. Not registry oriented whatsoever.
62     '''
63
64     def __init__(self, logger, gp_db, lp, creds, key, value):
65         super(inf_to_ldb, self).__init__(logger, gp_db, lp, creds, key, value)
66         try:
67             self.ldb = SamDB(self.lp.samdb_url(),
68                              session_info=system_session(),
69                              credentials=self.creds,
70                              lp=self.lp)
71         except (NameError, LdbError):
72             raise Exception('Failed to load SamDB for assigning Group Policy')
73
74     def ch_minPwdAge(self, val):
75         old_val = self.ldb.get_minPwdAge()
76         self.logger.info('KDC Minimum Password age was changed from %s to %s'
77                          % (old_val, val))
78         self.gp_db.store(str(self), self.attribute, str(old_val))
79         self.ldb.set_minPwdAge(val)
80
81     def ch_maxPwdAge(self, val):
82         old_val = self.ldb.get_maxPwdAge()
83         self.logger.info('KDC Maximum Password age was changed from %s to %s'
84                          % (old_val, val))
85         self.gp_db.store(str(self), self.attribute, str(old_val))
86         self.ldb.set_maxPwdAge(val)
87
88     def ch_minPwdLength(self, val):
89         old_val = self.ldb.get_minPwdLength()
90         self.logger.info(
91             'KDC Minimum Password length was changed from %s to %s'
92             % (old_val, val))
93         self.gp_db.store(str(self), self.attribute, str(old_val))
94         self.ldb.set_minPwdLength(val)
95
96     def ch_pwdProperties(self, val):
97         old_val = self.ldb.get_pwdProperties()
98         self.logger.info('KDC Password Properties were changed from %s to %s'
99                          % (old_val, val))
100         self.gp_db.store(str(self), self.attribute, str(old_val))
101         self.ldb.set_pwdProperties(val)
102
103     def days2rel_nttime(self):
104         seconds = 60
105         minutes = 60
106         hours = 24
107         sam_add = 10000000
108         val = (self.val)
109         val = int(val)
110         return str(-(val * seconds * minutes * hours * sam_add))
111
112     def mapper(self):
113         '''ldap value : samba setter'''
114         return {"minPwdAge": (self.ch_minPwdAge, self.days2rel_nttime),
115                 "maxPwdAge": (self.ch_maxPwdAge, self.days2rel_nttime),
116                 # Could be none, but I like the method assignment in
117                 # update_samba
118                 "minPwdLength": (self.ch_minPwdLength, self.explicit),
119                 "pwdProperties": (self.ch_pwdProperties, self.explicit),
120
121                 }
122
123     def __str__(self):
124         return 'System Access'
125
126
127 class gp_sec_ext(gp_inf_ext):
128     '''This class does the following two things:
129         1) Identifies the GPO if it has a certain kind of filepath,
130         2) Finally parses it.
131     '''
132
133     count = 0
134
135     def __str__(self):
136         return "Security GPO extension"
137
138     def apply_map(self):
139         return {"System Access": {"MinimumPasswordAge": ("minPwdAge",
140                                                          inf_to_ldb),
141                                   "MaximumPasswordAge": ("maxPwdAge",
142                                                          inf_to_ldb),
143                                   "MinimumPasswordLength": ("minPwdLength",
144                                                             inf_to_ldb),
145                                   "PasswordComplexity": ("pwdProperties",
146                                                          inf_to_ldb),
147                                   },
148                 "Kerberos Policy": {"MaxTicketAge": (
149                                         "kdc:user_ticket_lifetime",
150                                         inf_to_kdc_tdb
151                                     ),
152                                     "MaxServiceAge": (
153                                         "kdc:service_ticket_lifetime",
154                                         inf_to_kdc_tdb
155                                     ),
156                                     "MaxRenewAge": (
157                                         "kdc:renewal_lifetime",
158                                         inf_to_kdc_tdb
159                                     ),
160                                     }
161                 }
162
163     def process_group_policy(self, deleted_gpo_list, changed_gpo_list):
164         if self.lp.get('server role') != 'active directory domain controller':
165             return
166         inf_file = 'MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf'
167         apply_map = self.apply_map()
168         for gpo in deleted_gpo_list:
169             self.gp_db.set_guid(gpo[0])
170             for section in gpo[1].keys():
171                 current_section = apply_map.get(section)
172                 if not current_section:
173                     continue
174                 for key, value in gpo[1][section].items():
175                     setter = None
176                     for _, tup in current_section.items():
177                         if tup[0] == key:
178                             setter = tup[1]
179                     if setter:
180                         value = value.encode('ascii', 'ignore') \
181                              if value else value
182                         setter(self.logger, self.gp_db, self.lp, self.creds,
183                                key, value).delete()
184                         self.gp_db.delete(section, key)
185                         self.gp_db.commit()
186
187         for gpo in changed_gpo_list:
188             if gpo.file_sys_path:
189                 self.gp_db.set_guid(gpo.name)
190                 path = os.path.join(gpo.file_sys_path, inf_file)
191                 inf_conf = self.parse(path)
192                 if not inf_conf:
193                     continue
194                 for section in inf_conf.sections():
195                     current_section = apply_map.get(section)
196                     if not current_section:
197                         continue
198                     for key, value in inf_conf.items(section):
199                         if current_section.get(key):
200                             (att, setter) = current_section.get(key)
201                             value = value.encode('ascii', 'ignore')
202                             setter(self.logger, self.gp_db, self.lp,
203                                    self.creds, att, value).update_samba()
204                             self.gp_db.commit()
205