Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAS-127183 / 24.10 / Customer designated login banner #13892

Merged
merged 15 commits into from
Jul 3, 2024
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Add login_banner column

Revision ID: 1307a8e6a8b6
Revises: d8bfbf4e277e
Create Date: 2024-06-24 12:57:36.048308+00:00

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '1307a8e6a8b6'
down_revision = 'd8bfbf4e277e'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('system_advanced', schema=None) as batch_op:
batch_op.add_column(sa.Column('adv_login_banner', sa.Text(), nullable=False, server_default=''))



def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('system_advanced', schema=None) as batch_op:
batch_op.drop_column('adv_login_banner')
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

users = middleware.call_sync('user.query')
root_user = filter_list(users, [['username', '=', 'root']], {'get': True})

login_banner = render_ctx['system.advanced.login_banner']
%>\
Subsystem sftp internal-sftp -l ${ssh_config['sftp_log_level']} -f ${ssh_config['sftp_log_facility']}
% if 'Protocol' not in ssh_config['options']:
Expand Down Expand Up @@ -118,3 +118,6 @@ Match Group "${group}"
PasswordAuthentication yes
% endfor
% endif
% if login_banner != '':
Banner /etc/login_banner
% endif
6 changes: 6 additions & 0 deletions src/middlewared/middlewared/etc_files/login_banner.mako
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<%
login_banner = render_ctx['system.advanced.login_banner']
if login_banner == '':
raise FileShouldNotExist()
%>\
${login_banner}
2 changes: 2 additions & 0 deletions src/middlewared/middlewared/plugins/etc.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,12 +291,14 @@ class EtcService(Service):
{'method': 'ldap.config'},
{'method': 'auth.twofactor.config'},
{'method': 'interface.query'},
{'method': 'system.advanced.login_banner'},
],
"entries": [
{'type': 'mako', 'path': 'local/ssh/sshd_config', 'checkpoint': 'interface_sync'},
{'type': 'mako', 'path': 'pam.d/sshd', 'local_path': 'pam.d/sshd_linux'},
{'type': 'mako', 'path': 'local/users.oath', 'mode': 0o0600, 'checkpoint': 'pool_import'},
{'type': 'py', 'path': 'local/ssh/config'},
{'type': 'mako', 'path': 'login_banner', 'mode': 0o600},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also need to add system.advanced.login_banner to ctx above so that we only query once and provide to all scripts in this group.

]
},
'ntpd': [
Expand Down
14 changes: 13 additions & 1 deletion src/middlewared/middlewared/plugins/system_advanced/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import middlewared.sqlalchemy as sa

from middlewared.schema import accepts, Bool, Dict, Int, List, Patch, Password, returns, Str
from middlewared.service import ConfigService, private, ValidationErrors
from middlewared.service import ConfigService, private, no_authz_required, ValidationErrors
from middlewared.validators import Range
from middlewared.utils import run

Expand All @@ -32,6 +32,7 @@ class SystemAdvancedModel(sa.Model):
adv_anonstats = sa.Column(sa.Boolean(), default=True)
adv_anonstats_token = sa.Column(sa.Text())
adv_motd = sa.Column(sa.Text(), default='Welcome')
adv_login_banner = sa.Column(sa.Text(), default='')
adv_boot_scrub = sa.Column(sa.Integer(), default=7)
adv_fqdn_syslog = sa.Column(sa.Boolean(), default=False)
adv_sed_user = sa.Column(sa.String(120), default='user')
Expand Down Expand Up @@ -71,6 +72,7 @@ class Config:
Bool('debugkernel', required=True),
Bool('fqdn_syslog', required=True),
Str('motd', required=True),
Str('login_banner', required=True, max_length=4096),
Bool('powerdaemon', required=True),
Bool('serialconsole', required=True),
Str('serialport', required=True),
Expand Down Expand Up @@ -259,6 +261,9 @@ async def do_update(self, data):
if original_data['motd'] != config_data['motd']:
await self.middleware.call('etc.generate', 'motd')

if original_data['login_banner'] != config_data['login_banner']:
await self.middleware.call('service.reload', 'ssh')

if original_data['powerdaemon'] != config_data['powerdaemon']:
await self.middleware.call('service.restart', 'powerd')

Expand Down Expand Up @@ -310,3 +315,10 @@ async def sed_global_password(self):
'datastore.config', 'system.advanced', {'prefix': self._config.datastore_prefix}
))['sed_passwd']
return passwd if passwd else await self.middleware.call('kmip.sed_global_password')

@no_authz_required
@accepts()
@returns(Str())
def login_banner(self):
"""Returns user set login banner"""
return self.middleware.call_sync('datastore.config', 'system.advanced')['adv_login_banner']
10 changes: 10 additions & 0 deletions tests/api2/test_system_advanced_login_banner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from middlewared.test.integration.utils import call, ssh

def test_system_advanced_login_banner():
results = call('system.advanced.update', {
'login_banner': 'TrueNAS login banner.'
})
results = call('system.advanced.config')
assert results['login_banner'] == 'TrueNAS login banner.'
results = ssh('grep Banner /etc/ssh/sshd_config', complete_response=True)
assert results['result']
Loading