mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-08-08 09:21:48 +08:00
Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
182 lines
5.8 KiB
Bash
Executable File
182 lines
5.8 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Copyright (C) 2025 Nikos Mavrogiannopoulos
|
|
#
|
|
# This file is part of ocserv.
|
|
#
|
|
# ocserv 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 2 of the License, or (at
|
|
# your option) any later version.
|
|
#
|
|
# ocserv 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/>.
|
|
#
|
|
|
|
# Tests that PAM accounting (acct = "pam") gates VPN session establishment
|
|
# even when plain authentication succeeds.
|
|
#
|
|
# The accounting check runs during the VPN CONNECT phase (AUTH_COOKIE_REQ ->
|
|
# SECM_SESSION_OPEN), not during the initial password exchange that issues
|
|
# the cookie. A full connection attempt is therefore required to exercise it.
|
|
#
|
|
# Users:
|
|
# test - present in both test1.passwd AND the PAM passdb -> may connect
|
|
# test2 - present in test1.passwd but NOT in the PAM passdb -> blocked
|
|
|
|
OCCTL="${OCCTL:-../src/occtl/occtl}"
|
|
SERV="${SERV:-../src/ocserv}"
|
|
srcdir=${srcdir:-.}
|
|
PIDFILE=ocserv-pid.$$.tmp
|
|
CLIPID=oc-pid.$$.tmp
|
|
PATH=${PATH}:/usr/sbin
|
|
IP=$(which ip)
|
|
|
|
. `dirname $0`/common.sh
|
|
|
|
eval "${GETPORT}"
|
|
|
|
if test -z "${IP}"; then
|
|
echo "no IP tool is present"
|
|
exit 77
|
|
fi
|
|
|
|
if test "$(id -u)" != "0"; then
|
|
echo "This test must be run as root"
|
|
exit 77
|
|
fi
|
|
|
|
# Locate pam_wrapper shared library and pam_matrix module.
|
|
PAMWRAPDIR=$(pkg-config --variable=modules pam_wrapper 2>/dev/null)
|
|
if test -z "${PAMWRAPDIR}"; then
|
|
PAMWRAPDIR=/usr/lib/pam_wrapper
|
|
fi
|
|
LIBPAM_WRAPPER="${PAMWRAPDIR%/*}/libpam_wrapper.so"
|
|
if ! test -f "${LIBPAM_WRAPPER}"; then
|
|
# Try common Fedora/RHEL path
|
|
LIBPAM_WRAPPER=/usr/lib64/libpam_wrapper.so
|
|
fi
|
|
if ! test -f "${LIBPAM_WRAPPER}"; then
|
|
echo "pam_wrapper (libpam_wrapper.so) not available"
|
|
exit 77
|
|
fi
|
|
if ! test -f "${PAMWRAPDIR}/pam_matrix.so"; then
|
|
echo "pam_matrix.so not available in ${PAMWRAPDIR}"
|
|
exit 77
|
|
fi
|
|
|
|
# The generated PAM service config (ocserv) must exist in the build tree.
|
|
PAM_ACCT_OCSERV="${builddir}/data/pam-acct/ocserv"
|
|
if ! test -f "${PAM_ACCT_OCSERV}"; then
|
|
echo "Generated PAM service config not found: ${PAM_ACCT_OCSERV}"
|
|
exit 77
|
|
fi
|
|
|
|
echo "Testing PAM accounting with plain authentication..."
|
|
|
|
function finish {
|
|
echo " * Cleaning up..."
|
|
cleanup_client_server
|
|
test -n "${PAM_WRAPPER_SERVICE_DIR}" && rm -rf "${PAM_WRAPPER_SERVICE_DIR}" >/dev/null 2>&1
|
|
}
|
|
trap finish EXIT
|
|
|
|
OCCTL_SOCKET=./occtl-pam-acct-$$.socket
|
|
|
|
# Build PAM wrapper service directory for this test run.
|
|
PAM_WRAPPER_SERVICE_DIR=$(mktemp -d /tmp/pam-acct-XXXXXX)
|
|
cp "${PAM_ACCT_OCSERV}" "${PAM_WRAPPER_SERVICE_DIR}/ocserv"
|
|
sed -i "s|%PAM_WRAPPER_SERVICE_DIR%|${PAM_WRAPPER_SERVICE_DIR}|g" \
|
|
"${PAM_WRAPPER_SERVICE_DIR}/ocserv"
|
|
cp "${srcdir}/data/pam-acct/passdb.templ" "${PAM_WRAPPER_SERVICE_DIR}/passdb"
|
|
|
|
. `dirname $0`/random-net.sh
|
|
. `dirname $0`/ns.sh
|
|
|
|
update_config test-pass-pam-acct.config
|
|
if test "$VERBOSE" = 1; then
|
|
DEBUG="-d 3"
|
|
fi
|
|
|
|
# Start server with pam_wrapper preloaded so that the accounting module
|
|
# uses the fake PAM passdb instead of the real system PAM configuration.
|
|
${CMDNS2} env \
|
|
LD_PRELOAD="${LIBPAM_WRAPPER}" \
|
|
PAM_WRAPPER=1 \
|
|
PAM_WRAPPER_SERVICE_DIR="${PAM_WRAPPER_SERVICE_DIR}" \
|
|
${SERV} -p ${PIDFILE} -f -c ${CONFIG} ${DEBUG} &
|
|
PID=$!
|
|
|
|
sleep 4
|
|
|
|
# --- Positive test: user 'test' is in the PAM passdb, must connect ---
|
|
|
|
echo " * Getting cookie from ${ADDRESS}:${PORT} as 'test'..."
|
|
( echo "test" | ${CMDNS1} ${OPENCONNECT} ${ADDRESS}:${PORT} -u test \
|
|
--servercert=pin-sha256:xp3scfzy3rOQsv9NcOve/8YVVv+pHr4qNCXEXrNl5s8= \
|
|
--cookieonly )
|
|
if test $? != 0; then
|
|
echo "Could not get cookie for 'test'"
|
|
exit 1
|
|
fi
|
|
|
|
echo " * Connecting as 'test' (should succeed)..."
|
|
( echo "test" | ${CMDNS1} ${OPENCONNECT} ${ADDRESS}:${PORT} -u test \
|
|
--servercert=pin-sha256:xp3scfzy3rOQsv9NcOve/8YVVv+pHr4qNCXEXrNl5s8= \
|
|
-s /bin/true --pid-file=${CLIPID} --passwd-on-stdin -b )
|
|
if test $? != 0; then
|
|
echo "Could not connect as 'test'"
|
|
exit 1
|
|
fi
|
|
|
|
echo " * Verifying 'test' is listed as connected via occtl..."
|
|
${CMDNS2} ${OCCTL} -s ${OCCTL_SOCKET} -n show user test
|
|
if test $? != 0; then
|
|
echo "occtl did not find 'test' as connected"
|
|
kill $(cat ${CLIPID}) >/dev/null 2>&1
|
|
exit 1
|
|
fi
|
|
|
|
kill $(cat ${CLIPID}) >/dev/null 2>&1
|
|
rm -f ${CLIPID}
|
|
sleep 1
|
|
|
|
# --- Negative test: user 'test2' is NOT in the PAM passdb, must be blocked ---
|
|
|
|
echo " * Verifying 'test2' can still obtain a cookie (plain auth passes)..."
|
|
( echo "test2" | ${CMDNS1} ${OPENCONNECT} ${ADDRESS}:${PORT} -u test2 \
|
|
--servercert=pin-sha256:xp3scfzy3rOQsv9NcOve/8YVVv+pHr4qNCXEXrNl5s8= \
|
|
--cookieonly )
|
|
if test $? != 0; then
|
|
echo "test2 could not get a cookie; plain auth should pass independently of PAM accounting"
|
|
exit 1
|
|
fi
|
|
|
|
echo " * Attempting full VPN connection as 'test2' (PAM accounting must block)..."
|
|
# Run without -b so that the exit status reflects the CONNECT-phase outcome.
|
|
# pam_acct_mgmt returns PAM_PERM_DENIED for test2 (not in passdb) ->
|
|
# ocserv sends HTTP 401 during CONNECT -> openconnect exits non-zero
|
|
# before any TUN setup is attempted.
|
|
( echo "test2" | ${CMDNS1} ${OPENCONNECT} ${ADDRESS}:${PORT} -u test2 \
|
|
--servercert=pin-sha256:xp3scfzy3rOQsv9NcOve/8YVVv+pHr4qNCXEXrNl5s8= \
|
|
-s /bin/true --passwd-on-stdin )
|
|
if test $? = 0; then
|
|
echo "FAIL: 'test2' established a VPN session; PAM accounting did not block"
|
|
exit 1
|
|
fi
|
|
|
|
echo " * Verifying 'test2' is not listed as connected via occtl..."
|
|
${CMDNS2} ${OCCTL} -s ${OCCTL_SOCKET} -n show user test2
|
|
if test $? = 0; then
|
|
echo "FAIL: occtl found 'test2' as connected; PAM accounting did not block"
|
|
exit 1
|
|
fi
|
|
|
|
echo "PAM accounting correctly allowed 'test' and blocked 'test2'"
|
|
exit 0
|