@@ -40,9 +40,14 @@ LINUX_DEFAULT_PASS_MAX_DAYS = 99999
40
40
LINUX_DEFAULT_PASS_WARN_AGE = 7
41
41
42
42
# Ssh min-max values
43
- SSH_MIN_VALUES = {"authentication_retries" : 3 , "login_timeout" : 1 , "ports" : 1 }
44
- SSH_MAX_VALUES = {"authentication_retries" : 100 , "login_timeout" : 600 , "ports" : 65535 }
45
- SSH_CONFIG_NAMES = {"authentication_retries" : "MaxAuthTries" , "login_timeout" : "LoginGraceTime" }
43
+ SSH_MIN_VALUES = {"authentication_retries" : 3 , "login_timeout" : 1 , "ports" : 1 ,
44
+ "inactivity_timeout" : 0 , "max_sessions" : 0 }
45
+ SSH_MAX_VALUES = {"authentication_retries" : 100 , "login_timeout" : 600 ,
46
+ "ports" : 65535 , "inactivity_timeout" : 35000 ,
47
+ "max_sessions" : 100 }
48
+ SSH_CONFIG_NAMES = {"authentication_retries" : "MaxAuthTries" ,
49
+ "login_timeout" : "LoginGraceTime" , "ports" : "Port" ,
50
+ "inactivity_timeout" : "ClientAliveInterval" }
46
51
47
52
ACCOUNT_NAME = 0 # index of account name
48
53
AGE_DICT = { 'MAX_DAYS' : {'REGEX_DAYS' : r'^PASS_MAX_DAYS[ \t]*(?P<max_days>\d*)' , 'DAYS' : 'max_days' , 'CHAGE_FLAG' : '-M ' },
@@ -911,9 +916,15 @@ class SshServer(object):
911
916
syslog .syslog (syslog .LOG_ERR , "Ssh {} {} out of range" .format (key , value ))
912
917
elif key in SSH_CONFIG_NAMES :
913
918
# search replace configuration - if not in config file - append
919
+ if key == "inactivity_timeout" :
920
+ # translate min to sec.
921
+ value = int (value ) * 60
914
922
kv_str = "{} {}" .format (SSH_CONFIG_NAMES [key ], str (value )) # name +' '+ value format
915
923
modify_single_file_inplace (SSH_CONFG_TMP ,['-E' , "/^#?" + SSH_CONFIG_NAMES [key ]+ "/{h;s/.*/" +
916
924
kv_str + "/};${x;/^$/{s//" + kv_str + "/;H};x}" ])
925
+ elif key in ['max_sessions' ]:
926
+ # Ignore, these parameters handled in other modules
927
+ continue
917
928
else :
918
929
syslog .syslog (syslog .LOG_ERR , "Failed to update sshd config file - wrong key {}" .format (key ))
919
930
@@ -1128,16 +1139,31 @@ class PamLimitsCfg(object):
1128
1139
self .config_db = config_db
1129
1140
self .hwsku = ""
1130
1141
self .type = ""
1142
+ self .max_sessions = None
1131
1143
1132
1144
# Load config from ConfigDb and render config file/
1133
1145
def update_config_file (self ):
1134
1146
device_metadata = self .config_db .get_table ('DEVICE_METADATA' )
1135
- if "localhost" not in device_metadata :
1147
+ ssh_server_policies = {}
1148
+ try :
1149
+ ssh_server_policies = self .config_db .get_table ('SSH_SERVER' )
1150
+ except KeyError :
1151
+ """Dont throw except in case we don`t have SSH_SERVER config."""
1152
+ pass
1153
+
1154
+ if "localhost" not in device_metadata and "POLICIES" not in ssh_server_policies :
1136
1155
return
1137
1156
1138
1157
self .read_localhost_config (device_metadata ["localhost" ])
1158
+ self .read_max_sessions_config (ssh_server_policies .get ("POLICIES" , None ))
1139
1159
self .render_conf_file ()
1140
1160
1161
+ # Read max_sessions config
1162
+ def read_max_sessions_config (self , ssh_server_policies ):
1163
+ if ssh_server_policies is not None :
1164
+ max_sess_cfg = ssh_server_policies .get ('max_sessions' , 0 )
1165
+ self .max_sessions = max_sess_cfg if max_sess_cfg != 0 else None
1166
+
1141
1167
# Read localhost config
1142
1168
def read_localhost_config (self , localhost ):
1143
1169
if "hwsku" in localhost :
@@ -1154,7 +1180,6 @@ class PamLimitsCfg(object):
1154
1180
def render_conf_file (self ):
1155
1181
env = jinja2 .Environment (loader = jinja2 .FileSystemLoader ('/' ), trim_blocks = True )
1156
1182
env .filters ['sub' ] = sub
1157
-
1158
1183
try :
1159
1184
template_file = os .path .abspath (PAM_LIMITS_CONF_TEMPLATE )
1160
1185
template = env .get_template (template_file )
@@ -1168,7 +1193,8 @@ class PamLimitsCfg(object):
1168
1193
template = env .get_template (template_file )
1169
1194
limits_conf = template .render (
1170
1195
hwsku = self .hwsku ,
1171
- type = self .type )
1196
+ type = self .type ,
1197
+ max_sessions = self .max_sessions )
1172
1198
with open (LIMITS_CONF , 'w' ) as f :
1173
1199
f .write (limits_conf )
1174
1200
except Exception as e :
@@ -1500,6 +1526,45 @@ class FipsCfg(object):
1500
1526
syslog .syslog (syslog .LOG_INFO , f'FipsCfg: update the FIPS enforce option { self .enforce } .' )
1501
1527
loader .set_fips (image , self .enforce )
1502
1528
1529
+
1530
+ class SerialConsoleCfg :
1531
+
1532
+ def __init__ (self ):
1533
+ self .cache = {}
1534
+
1535
+ def load (self , cli_sessions_conf ):
1536
+ self .cache = cli_sessions_conf or {}
1537
+ syslog .syslog (syslog .LOG_INFO ,
1538
+ f'SerialConsoleCfg: Initial config: { self .cache } ' )
1539
+
1540
+ def update_serial_console_cfg (self , key , data ):
1541
+ '''
1542
+ Apply config flow:
1543
+ inactivity_timeout | set here AND in ssh_config flow | serial-config.service restarted.
1544
+ max_sessions | set by PamLimitsCfg | serial-config.service DOESNT restarted.
1545
+ sysrq_capabilities | set here | serial-config.service restarted.
1546
+ '''
1547
+
1548
+ # max_sessions applied in limits.conf by PamLimitsCfg
1549
+ if key in ['max_sessions' ]:
1550
+ syslog .syslog (syslog .LOG_DEBUG ,
1551
+ f'SerialConsoleCfg: skip max_sessions in SerialConsoleCfg apply config handler' )
1552
+ return
1553
+
1554
+ if self .cache .get (key , {}) != data :
1555
+ ''' Config changed, need to restart the serial-config.service '''
1556
+ syslog .syslog (syslog .LOG_INFO , f'Set serial-config parameter { key } value: { data } ' )
1557
+ try :
1558
+ run_cmd (['sudo' , 'service' , 'serial-config' , 'restart' ],
1559
+ True , True )
1560
+ except Exception :
1561
+ syslog .syslog (syslog .LOG_ERR , f'Failed to update { key } serial-config.service config' )
1562
+ return
1563
+ self .cache .update ({key : data })
1564
+
1565
+ return
1566
+
1567
+
1503
1568
class HostConfigDaemon :
1504
1569
def __init__ (self ):
1505
1570
self .state_db_conn = DBConnector (STATE_DB , 0 )
@@ -1551,6 +1616,9 @@ class HostConfigDaemon:
1551
1616
# Initialize FipsCfg
1552
1617
self .fipscfg = FipsCfg (self .state_db_conn )
1553
1618
1619
+ # Initialize SerialConsoleCfg
1620
+ self .serialconscfg = SerialConsoleCfg ()
1621
+
1554
1622
def load (self , init_data ):
1555
1623
aaa = init_data ['AAA' ]
1556
1624
tacacs_global = init_data ['TACPLUS' ]
@@ -1571,6 +1639,7 @@ class HostConfigDaemon:
1571
1639
ntp_global = init_data .get (swsscommon .CFG_NTP_GLOBAL_TABLE_NAME )
1572
1640
ntp_servers = init_data .get (swsscommon .CFG_NTP_SERVER_TABLE_NAME )
1573
1641
ntp_keys = init_data .get (swsscommon .CFG_NTP_KEY_TABLE_NAME )
1642
+ serial_console = init_data .get ('SERIAL_CONSOLE' , {})
1574
1643
1575
1644
self .aaacfg .load (aaa , tacacs_global , tacacs_server , radius_global , radius_server )
1576
1645
self .iptables .load (lpbk_table )
@@ -1579,11 +1648,12 @@ class HostConfigDaemon:
1579
1648
self .sshscfg .load (ssh_server )
1580
1649
self .devmetacfg .load (dev_meta )
1581
1650
self .mgmtifacecfg .load (mgmt_ifc , mgmt_vrf )
1582
-
1583
1651
self .rsyslogcfg .load (syslog_cfg , syslog_srv )
1584
1652
self .dnscfg .load (dns )
1585
1653
self .fipscfg .load (fips_cfg )
1586
1654
self .ntpcfg .load (ntp_global , ntp_servers , ntp_keys )
1655
+ self .serialconscfg .load (serial_console )
1656
+ self .pamLimitsCfg .update_config_file ()
1587
1657
1588
1658
# Update AAA with the hostname
1589
1659
self .aaacfg .hostname_update (self .devmetacfg .hostname )
@@ -1605,6 +1675,8 @@ class HostConfigDaemon:
1605
1675
1606
1676
def ssh_handler (self , key , op , data ):
1607
1677
self .sshscfg .policies_update (key , data )
1678
+ self .pamLimitsCfg .update_config_file ()
1679
+
1608
1680
syslog .syslog (syslog .LOG_INFO , 'SSH Update: key: {}, op: {}, data: {}' .format (key , op , data ))
1609
1681
1610
1682
def tacacs_server_handler (self , key , op , data ):
@@ -1716,6 +1788,10 @@ class HostConfigDaemon:
1716
1788
data = self .config_db .get_table ("FIPS" )
1717
1789
self .fipscfg .fips_handler (data )
1718
1790
1791
+ def serial_console_config_handler (self , key , op , data ):
1792
+ syslog .syslog (syslog .LOG_INFO , 'SERIAL_CONSOLE table handler...' )
1793
+ self .serialconscfg .update_serial_console_cfg (key , data )
1794
+
1719
1795
def wait_till_system_init_done (self ):
1720
1796
# No need to print the output in the log file so using the "--quiet"
1721
1797
# flag
@@ -1742,6 +1818,8 @@ class HostConfigDaemon:
1742
1818
self .config_db .subscribe ('RADIUS_SERVER' , make_callback (self .radius_server_handler ))
1743
1819
self .config_db .subscribe ('PASSW_HARDENING' , make_callback (self .passwh_handler ))
1744
1820
self .config_db .subscribe ('SSH_SERVER' , make_callback (self .ssh_handler ))
1821
+ # Handle SERIAL_CONSOLE
1822
+ self .config_db .subscribe ('SERIAL_CONSOLE' , make_callback (self .serial_console_config_handler ))
1745
1823
# Handle IPTables configuration
1746
1824
self .config_db .subscribe ('LOOPBACK_INTERFACE' , make_callback (self .lpbk_handler ))
1747
1825
# Handle updates to src intf changes in radius
0 commit comments