2018-03-12 18:44:38 +03:00
# gp_sec_ext kdc gpo policy
# Copyright (C) Luke Morrison <luc785@.hotmail.com> 2013
# Copyright (C) David Mulder <dmulder@suse.com> 2018
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os . path
2020-07-08 23:50:27 +03:00
from samba . gpclass import gp_inf_ext
2018-05-04 23:09:30 +03:00
from samba . auth import system_session
2020-09-11 23:29:46 +03:00
from samba . common import get_string
2018-05-04 23:09:30 +03:00
try :
from ldb import LdbError
from samba . samdb import SamDB
except ImportError :
pass
2018-03-12 18:44:38 +03:00
2020-08-07 23:09:27 +03:00
def mins_to_hours ( val ) :
return ' %d ' % ( int ( val ) / 60 )
def days_to_hours ( val ) :
return ' %d ' % ( int ( val ) * 24 )
def days2rel_nttime ( val ) :
seconds = 60
minutes = 60
hours = 24
sam_add = 10000000
val = int ( val )
return str ( - ( val * seconds * minutes * hours * sam_add ) )
2018-07-30 09:20:39 +03:00
2020-06-27 00:34:02 +03:00
class gp_krb_ext ( gp_inf_ext ) :
apply_map = { ' MaxTicketAge ' : ' kdc:user_ticket_lifetime ' ,
' MaxServiceAge ' : ' kdc:service_ticket_lifetime ' ,
' MaxRenewAge ' : ' kdc:renewal_lifetime ' }
def process_group_policy ( self , deleted_gpo_list , changed_gpo_list ) :
if self . lp . get ( ' server role ' ) != ' active directory domain controller ' :
return
inf_file = ' MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf '
2020-08-06 22:30:36 +03:00
for guid , settings in deleted_gpo_list :
self . gp_db . set_guid ( guid )
for section in settings . keys ( ) :
2020-06-27 00:34:02 +03:00
if section == str ( self ) :
2020-08-06 22:30:36 +03:00
for att , value in settings [ section ] . items ( ) :
2020-08-07 23:15:30 +03:00
self . set_kdc_tdb ( att , value )
2020-06-27 00:34:02 +03:00
self . gp_db . delete ( section , att )
self . gp_db . commit ( )
for gpo in changed_gpo_list :
if gpo . file_sys_path :
self . gp_db . set_guid ( gpo . name )
path = os . path . join ( gpo . file_sys_path , inf_file )
inf_conf = self . parse ( path )
if not inf_conf :
continue
for section in inf_conf . sections ( ) :
if section == str ( self ) :
for key , value in inf_conf . items ( section ) :
att = gp_krb_ext . apply_map [ key ]
2020-08-07 23:15:30 +03:00
value_func = self . mapper ( ) . get ( att )
self . set_kdc_tdb ( att , value_func ( value ) )
2020-06-27 00:34:02 +03:00
self . gp_db . commit ( )
def set_kdc_tdb ( self , attribute , val ) :
old_val = self . gp_db . gpostore . get ( attribute )
self . logger . info ( ' %s was changed from %s to %s ' % ( attribute ,
2018-03-12 18:44:38 +03:00
old_val , val ) )
if val is not None :
2020-06-27 00:34:02 +03:00
self . gp_db . gpostore . store ( attribute , get_string ( val ) )
self . gp_db . store ( str ( self ) , attribute , get_string ( old_val ) \
if old_val else None )
2018-03-12 18:44:38 +03:00
else :
2020-06-27 00:34:02 +03:00
self . gp_db . gpostore . delete ( attribute )
self . gp_db . delete ( str ( self ) , attribute )
2018-03-12 18:44:38 +03:00
def mapper ( self ) :
2020-08-07 23:15:30 +03:00
return { ' kdc:user_ticket_lifetime ' : lambda val : val ,
' kdc:service_ticket_lifetime ' : mins_to_hours ,
' kdc:renewal_lifetime ' : days_to_hours ,
2018-09-03 16:05:31 +03:00
}
2018-03-12 18:44:38 +03:00
def __str__ ( self ) :
return ' Kerberos Policy '
2020-06-27 00:34:02 +03:00
def rsop ( self , gpo ) :
output = { }
2020-08-07 20:09:17 +03:00
if self . lp . get ( ' server role ' ) != ' active directory domain controller ' :
return output
2020-06-27 00:34:02 +03:00
inf_file = ' MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf '
if gpo . file_sys_path :
path = os . path . join ( gpo . file_sys_path , inf_file )
inf_conf = self . parse ( path )
if not inf_conf :
return output
2020-12-15 22:48:30 +03:00
if str ( self ) in inf_conf . sections ( ) :
section = str ( self )
2020-06-27 00:34:02 +03:00
output [ section ] = { k : v for k , v in inf_conf . items ( section ) \
if gp_krb_ext . apply_map . get ( k ) }
return output
2018-07-30 09:20:39 +03:00
2020-07-08 23:48:45 +03:00
class gp_access_ext ( gp_inf_ext ) :
2018-03-12 18:44:38 +03:00
''' This class takes the .inf file parameter (essentially a GPO file mapped
to a GUID ) , hashmaps it to the Samba parameter , which then uses an ldb
object to update the parameter to Samba4 . Not registry oriented whatsoever .
'''
2021-02-24 22:35:10 +03:00
def load_ldb ( self ) :
2018-05-04 23:09:30 +03:00
try :
self . ldb = SamDB ( self . lp . samdb_url ( ) ,
session_info = system_session ( ) ,
credentials = self . creds ,
lp = self . lp )
except ( NameError , LdbError ) :
raise Exception ( ' Failed to load SamDB for assigning Group Policy ' )
2020-07-08 23:48:45 +03:00
apply_map = { ' MinimumPasswordAge ' : ' minPwdAge ' ,
' MaximumPasswordAge ' : ' maxPwdAge ' ,
' MinimumPasswordLength ' : ' minPwdLength ' ,
' PasswordComplexity ' : ' pwdProperties ' }
def process_group_policy ( self , deleted_gpo_list , changed_gpo_list ) :
if self . lp . get ( ' server role ' ) != ' active directory domain controller ' :
return
2021-02-24 22:35:10 +03:00
self . load_ldb ( )
2020-07-08 23:48:45 +03:00
inf_file = ' MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf '
2020-08-06 22:30:36 +03:00
for guid , settings in deleted_gpo_list :
self . gp_db . set_guid ( guid )
for section in settings . keys ( ) :
2020-07-08 23:48:45 +03:00
if section == str ( self ) :
2020-08-06 22:30:36 +03:00
for att , value in settings [ section ] . items ( ) :
2020-07-08 23:48:45 +03:00
update_samba , _ = self . mapper ( ) . get ( att )
update_samba ( att , value )
self . gp_db . delete ( section , att )
self . gp_db . commit ( )
for gpo in changed_gpo_list :
if gpo . file_sys_path :
self . gp_db . set_guid ( gpo . name )
path = os . path . join ( gpo . file_sys_path , inf_file )
inf_conf = self . parse ( path )
if not inf_conf :
continue
for section in inf_conf . sections ( ) :
if section == str ( self ) :
for key , value in inf_conf . items ( section ) :
att = gp_access_ext . apply_map [ key ]
( update_samba , value_func ) = self . mapper ( ) . get ( att )
update_samba ( att , value_func ( value ) )
self . gp_db . commit ( )
def ch_minPwdAge ( self , attribute , val ) :
2018-03-12 18:44:38 +03:00
old_val = self . ldb . get_minPwdAge ( )
2018-07-30 09:22:01 +03:00
self . logger . info ( ' KDC Minimum Password age was changed from %s to %s '
2018-03-12 18:44:38 +03:00
% ( old_val , val ) )
2020-07-08 23:48:45 +03:00
self . gp_db . store ( str ( self ) , attribute , str ( old_val ) )
2018-03-12 18:44:38 +03:00
self . ldb . set_minPwdAge ( val )
2020-07-08 23:48:45 +03:00
def ch_maxPwdAge ( self , attribute , val ) :
2018-03-12 18:44:38 +03:00
old_val = self . ldb . get_maxPwdAge ( )
2018-07-30 09:22:01 +03:00
self . logger . info ( ' KDC Maximum Password age was changed from %s to %s '
2018-03-12 18:44:38 +03:00
% ( old_val , val ) )
2020-07-08 23:48:45 +03:00
self . gp_db . store ( str ( self ) , attribute , str ( old_val ) )
2018-03-12 18:44:38 +03:00
self . ldb . set_maxPwdAge ( val )
2020-07-08 23:48:45 +03:00
def ch_minPwdLength ( self , attribute , val ) :
2018-03-12 18:44:38 +03:00
old_val = self . ldb . get_minPwdLength ( )
self . logger . info (
2018-07-30 09:22:01 +03:00
' KDC Minimum Password length was changed from %s to %s '
2018-07-30 09:16:26 +03:00
% ( old_val , val ) )
2020-07-08 23:48:45 +03:00
self . gp_db . store ( str ( self ) , attribute , str ( old_val ) )
2018-03-12 18:44:38 +03:00
self . ldb . set_minPwdLength ( val )
2020-07-08 23:48:45 +03:00
def ch_pwdProperties ( self , attribute , val ) :
2018-03-12 18:44:38 +03:00
old_val = self . ldb . get_pwdProperties ( )
2018-07-30 09:22:01 +03:00
self . logger . info ( ' KDC Password Properties were changed from %s to %s '
2018-03-12 18:44:38 +03:00
% ( old_val , val ) )
2020-07-08 23:48:45 +03:00
self . gp_db . store ( str ( self ) , attribute , str ( old_val ) )
2018-03-12 18:44:38 +03:00
self . ldb . set_pwdProperties ( val )
def mapper ( self ) :
''' ldap value : samba setter '''
2020-08-07 23:09:27 +03:00
return { " minPwdAge " : ( self . ch_minPwdAge , days2rel_nttime ) ,
" maxPwdAge " : ( self . ch_maxPwdAge , days2rel_nttime ) ,
2018-09-03 16:05:48 +03:00
# Could be none, but I like the method assignment in
# update_samba
2020-07-08 23:48:45 +03:00
" minPwdLength " : ( self . ch_minPwdLength , lambda val : val ) ,
" pwdProperties " : ( self . ch_pwdProperties , lambda val : val ) ,
2018-03-12 18:44:38 +03:00
2018-09-03 16:05:31 +03:00
}
2018-03-12 18:44:38 +03:00
def __str__ ( self ) :
return ' System Access '
2020-07-06 20:16:14 +03:00
def rsop ( self , gpo ) :
output = { }
2020-08-07 20:09:17 +03:00
if self . lp . get ( ' server role ' ) != ' active directory domain controller ' :
return output
2020-07-06 20:16:14 +03:00
inf_file = ' MACHINE/Microsoft/Windows NT/SecEdit/GptTmpl.inf '
if gpo . file_sys_path :
path = os . path . join ( gpo . file_sys_path , inf_file )
inf_conf = self . parse ( path )
if not inf_conf :
return output
2020-12-15 22:48:30 +03:00
if str ( self ) in inf_conf . sections ( ) :
section = str ( self )
2020-07-06 20:16:14 +03:00
output [ section ] = { k : v for k , v in inf_conf . items ( section ) \
2020-07-08 23:48:45 +03:00
if gp_access_ext . apply_map . get ( k ) }
2020-07-06 20:16:14 +03:00
return output