Skip to content

Commit

Permalink
Refactor PAM config generation
Browse files Browse the repository at this point in the history
This commit refactors how we generate custom PAM configuration
lines so as to force them to run though a parser, and adds tests
for said parser. pam_tty_audit is also enabled for interactive
sessions for root account if for some reason a user gets interactive
root session when GPOS STIG is enabled (this should never happen).
  • Loading branch information
anodos325 committed Dec 16, 2024
1 parent 33f5db0 commit 2d9b389
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 265 deletions.
23 changes: 19 additions & 4 deletions src/middlewared/middlewared/etc_files/pam.d/common-account.mako
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,27 @@
# the central access policy for use on the system. The default is to
# only deny service to users whose accounts are expired in /etc/shadow.
#
<%namespace name="pam" file="pam.inc.mako" />\
<%
dsp = pam.getDirectoryServicePam(middleware=middleware, render_ctx=render_ctx).pam_account()
from middlewared.utils.directoryservices.constants import DSType
from middlewared.utils.pam import STANDALONE_ACCOUNT, AD_ACCOUNT, SSS_ACCOUNT
match (dstype := render_ctx['directoryservices.status']['type']):
# dstype of None means standalone server
case None:
conf = STANDALONE_ACCOUNT
case DSType.AD.value:
conf = AD_ACCOUNT
case DSType.LDAP.value | DSType.IPA.value:
conf = SSS_ACCOUNT
case _:
raise TypeError(f'{dstype}: unknown DSType')
%>\

${'\n'.join(dsp['primary'])}
% if conf.primary:
${'\n'.join(line.as_conf() for line in conf.primary)}
% endif
account requisite pam_deny.so
account required pam_permit.so
${'\n'.join(dsp['additional'])}
% if conf.secondary:
${'\n'.join(line.as_conf() for line in conf.secondary)}
% endif
23 changes: 19 additions & 4 deletions src/middlewared/middlewared/etc_files/pam.d/common-auth.mako
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,26 @@
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.

<%namespace name="pam" file="pam.inc.mako" />\
<%
dsp = pam.getDirectoryServicePam(middleware=middleware, render_ctx=render_ctx).pam_auth()
from middlewared.utils.directoryservices.constants import DSType
from middlewared.utils.pam import STANDALONE_AUTH, AD_AUTH, SSS_AUTH
match (dstype := render_ctx['directoryservices.status']['type']):
# dstype of None means standalone server
case None:
conf = STANDALONE_AUTH
case DSType.AD.value:
conf = AD_AUTH
case DSType.LDAP.value | DSType.IPA.value:
conf = SSS_AUTH
case _:
raise TypeError(f'{dstype}: unknown DSType')
%>\

${'\n'.join(dsp['primary'])}
% if conf.primary:
${'\n'.join(line.as_conf() for line in conf.primary)}
% endif
@include common-auth-unix
${'\n'.join(dsp['additional'])}
% if conf.secondary:
${'\n'.join(line.as_conf() for line in conf.secondary)}
% endif
18 changes: 2 additions & 16 deletions src/middlewared/middlewared/etc_files/pam.d/common-password.mako
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,9 @@
# This file is included from other service-specific PAM config files,
# and should contain a list of modules that define the services to be
# used to change user passwords. The default is pam_unix.

# Explanation of pam_unix options:
#
# The "sha512" option enables salted SHA512 passwords. Without this option,
# the default is Unix crypt. Prior releases used the option "md5".
#
# The "obscure" option replaces the old `OBSCURE_CHECKS_ENAB' option in
# login.defs.
#
# See the pam_unix manpage for other options.

<%namespace name="pam" file="pam.inc.mako" />\
<%
dsp = pam.getDirectoryServicePam(middleware=middleware, render_ctx=render_ctx).pam_password()
%>\
# The ability to change password via PAM is disabled on TrueNAS. Any account
# password changes should be made through the TrueNAS middleware

${'\n'.join(dsp['primary'])}
password requisite pam_deny.so
password required pam_permit.so
${'\n'.join(dsp['additional'])}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,29 @@
# and should contain a list of modules that define tasks to be performed
# at the start and end of all non-interactive sessions.
#
<%namespace name="pam" file="pam.inc.mako" />\
<%
dsp = pam.getDirectoryServicePam(middleware=middleware, render_ctx=render_ctx).pam_session()
from middlewared.utils.directoryservices.constants import DSType
from middlewared.utils.pam import STANDALONE_SESSION, AD_SESSION, SSS_SESSION
match (dstype := render_ctx['directoryservices.status']['type']):
# dstype of None means standalone server
case None:
conf = STANDALONE_SESSION
case DSType.AD.value:
conf = AD_SESSION
case DSType.LDAP.value | DSType.IPA.value:
conf = SSS_SESSION
case _:
raise TypeError(f'{dstype}: unknown DSType')
%>\

${'\n'.join(dsp['primary'])}
% if conf.primary:
${'\n'.join(line.as_conf() for line in conf.primary)}
% endif
session [default=1] pam_permit.so
session requisite pam_deny.so
session required pam_permit.so
${'\n'.join(dsp['additional'])}
% if conf.secondary:
${'\n'.join(line.as_conf() for line in conf.secondary)}
% endif

32 changes: 27 additions & 5 deletions src/middlewared/middlewared/etc_files/pam.d/common-session.mako
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,36 @@
# at the start and end of sessions of *any* kind (both interactive and
# non-interactive).

<%namespace name="pam" file="pam.inc.mako" />\
<%
dsp = pam.getDirectoryServicePam(middleware=middleware, render_ctx=render_ctx).pam_session()
%>\
from middlewared.utils.directoryservices.constants import DSType
from middlewared.utils.pam import TTY_AUDIT_LINE, STANDALONE_SESSION, AD_SESSION, SSS_SESSION
tty_audit_line = None
${'\n'.join(dsp['primary'])}
match (dstype := render_ctx['directoryservices.status']['type']):
# dstype of None means standalone server
case None:
conf = STANDALONE_SESSION
case DSType.AD.value:
conf = AD_SESSION
case DSType.LDAP.value | DSType.IPA.value:
conf = SSS_SESSION
case _:
raise TypeError(f'{dstype}: unknown DSType')
if render_ctx['system.security.config']['enable_gpos_stig']:
tty_audit_line = TTY_AUDIT_LINE
%>\
% if conf.tty_audit_line:
${TTY_AUDIT_LINE.as_conf()}
% endif
% if conf.primary:
${'\n'.join(line.as_conf() for line in conf.primary)}
% endif
session [default=1] pam_permit.so
session requisite pam_deny.so
session required pam_permit.so
session optional pam_systemd.so
${'\n'.join(dsp['additional'])}
% if conf.secondary:
${'\n'.join(line.as_conf() for line in conf.secondary)}
% endif
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<%
from middlewared.utils import filter_list
from middlewared.utils.auth import LEGACY_API_KEY_USERNAME
from middlewared.utils.pam import STANDALONE_AUTH
ds_auth = render_ctx['datastore.config']['stg_ds_auth']
truenas_admin_string = ''
Expand All @@ -18,11 +19,7 @@ auth [success=1 default=die] pam_tdb.so ${truenas_admin_string}
%if ds_auth:
@include common-account
%else:
<%namespace name="pam" file="pam.inc.mako" />\
<%
dsp = pam.getNoDirectoryServicePam().pam_account()
%>\
${'\n'.join(dsp['primary'])}
${'\n'.join(line.as_conf() for line in STANDALONE_AUTH.primary)}
@include common-account-unix
%endif
password required pam_deny.so
Expand Down
8 changes: 3 additions & 5 deletions src/middlewared/middlewared/etc_files/pam.d/middleware.mako
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
<%
from middlewared.utils.pam import STANDALONE_AUTH
ds_auth = render_ctx['datastore.config']['stg_ds_auth']
%>\
# PAM configuration for the middleware (Web UI / API login)

%if ds_auth:
@include common-auth
%else:
<%namespace name="pam" file="pam.inc.mako" />\
<%
dsp = pam.getNoDirectoryServicePam().pam_auth()
%>\
${'\n'.join(dsp['primary'])}
${'\n'.join(line.as_conf() for line in STANDALONE_AUTH.primary)}
@include common-auth-unix
%endif
@include common-account
Expand Down
Loading

0 comments on commit 2d9b389

Please sign in to comment.