RADIUS Management User Authentication Feature (#7284)
Why I did it HLD: https://github.com/Azure/SONiC/blob/master/doc/aaa/radius_authentication.md CLI: In a separate PR. How I did it How to verify it UT: src/sonic-host-services/tests/hostcfgd/hostcfgd_radius_test.py
This commit is contained in:
parent
990b1127a7
commit
ec9101f9c5
@ -299,6 +299,16 @@ sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/libnss-tacplus_*.deb || \
|
|||||||
sudo LANG=C chroot $FILESYSTEM_ROOT pam-auth-update --remove tacplus
|
sudo LANG=C chroot $FILESYSTEM_ROOT pam-auth-update --remove tacplus
|
||||||
sudo sed -i -e '/^passwd/s/ tacplus//' $FILESYSTEM_ROOT/etc/nsswitch.conf
|
sudo sed -i -e '/^passwd/s/ tacplus//' $FILESYSTEM_ROOT/etc/nsswitch.conf
|
||||||
|
|
||||||
|
# Install pam-radius-auth and nss-radius
|
||||||
|
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/libpam-radius-auth_*.deb || \
|
||||||
|
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f
|
||||||
|
sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/libnss-radius_*.deb || \
|
||||||
|
sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f
|
||||||
|
# Disable radius by default
|
||||||
|
# radius does not have any profiles
|
||||||
|
#sudo LANG=C chroot $FILESYSTEM_ROOT pam-auth-update --remove radius tacplus
|
||||||
|
sudo sed -i -e '/^passwd/s/ radius//' $FILESYSTEM_ROOT/etc/nsswitch.conf
|
||||||
|
|
||||||
# Install a custom version of kdump-tools (and its dependencies via 'apt-get -y install -f')
|
# Install a custom version of kdump-tools (and its dependencies via 'apt-get -y install -f')
|
||||||
if [[ $CONFIGURED_ARCH == amd64 ]]; then
|
if [[ $CONFIGURED_ARCH == amd64 ]]; then
|
||||||
sudo DEBIAN_FRONTEND=noninteractive dpkg --root=$FILESYSTEM_ROOT -i $debs_path/kdump-tools_*.deb || \
|
sudo DEBIAN_FRONTEND=noninteractive dpkg --root=$FILESYSTEM_ROOT -i $debs_path/kdump-tools_*.deb || \
|
||||||
|
13
rules/radius.dep
Normal file
13
rules/radius.dep
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
SPATH := $($(LIBPAM_RADIUS)_SRC_PATH)
|
||||||
|
DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/radius.mk rules/radius.dep
|
||||||
|
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
|
||||||
|
DEP_FILES += $(shell git ls-files $(SPATH))
|
||||||
|
|
||||||
|
$(LIBPAM_RADIUS)_CACHE_MODE := GIT_CONTENT_SHA
|
||||||
|
$(LIBPAM_RADIUS)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
|
||||||
|
$(LIBPAM_RADIUS)_DEP_FILES := $(DEP_FILES)
|
||||||
|
|
||||||
|
$(LIBNSS_RADIUS)_CACHE_MODE := GIT_CONTENT_SHA
|
||||||
|
$(LIBNSS_RADIUS)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
|
||||||
|
$(LIBNSS_RADIUS)_DEP_FILES := $(DEP_FILES)
|
24
rules/radius.mk
Normal file
24
rules/radius.mk
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# libpam-radius-auth packages
|
||||||
|
|
||||||
|
PAM_RADIUS_VERSION = 1.4.1-1
|
||||||
|
|
||||||
|
export PAM_RADIUS_VERSION
|
||||||
|
|
||||||
|
LIBPAM_RADIUS = libpam-radius-auth_$(PAM_RADIUS_VERSION)_amd64.deb
|
||||||
|
$(LIBPAM_RADIUS)_SRC_PATH = $(SRC_PATH)/radius/pam
|
||||||
|
SONIC_MAKE_DEBS += $(LIBPAM_RADIUS)
|
||||||
|
|
||||||
|
SONIC_STRETCH_DEBS += $(LIBPAM_RADIUS)
|
||||||
|
|
||||||
|
# libnss-radius packages
|
||||||
|
|
||||||
|
NSS_RADIUS_VERSION = 1.0.1-1
|
||||||
|
|
||||||
|
export NSS_RADIUS_VERSION
|
||||||
|
|
||||||
|
LIBNSS_RADIUS = libnss-radius_$(NSS_RADIUS_VERSION)_amd64.deb
|
||||||
|
$(LIBNSS_RADIUS)_SRC_PATH = $(SRC_PATH)/radius/nss
|
||||||
|
SONIC_MAKE_DEBS += $(LIBNSS_RADIUS)
|
||||||
|
|
||||||
|
SONIC_STRETCH_DEBS += $(LIBNSS_RADIUS)
|
||||||
|
|
2
slave.mk
2
slave.mk
@ -858,6 +858,8 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \
|
|||||||
$(IFUPDOWN2) \
|
$(IFUPDOWN2) \
|
||||||
$(KDUMP_TOOLS) \
|
$(KDUMP_TOOLS) \
|
||||||
$(NTP) \
|
$(NTP) \
|
||||||
|
$(LIBPAM_RADIUS) \
|
||||||
|
$(LIBNSS_RADIUS) \
|
||||||
$(LIBPAM_TACPLUS) \
|
$(LIBPAM_TACPLUS) \
|
||||||
$(LIBNSS_TACPLUS) \
|
$(LIBNSS_TACPLUS) \
|
||||||
$(MONIT) \
|
$(MONIT) \
|
||||||
|
23
src/radius/nss/Makefile
Normal file
23
src/radius/nss/Makefile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.ONESHELL:
|
||||||
|
SHELL = /bin/bash
|
||||||
|
.SHELLFLAGS += -e
|
||||||
|
|
||||||
|
MAIN_TARGET = libnss-radius_$(NSS_RADIUS_VERSION)_amd64.deb
|
||||||
|
|
||||||
|
$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
|
||||||
|
pushd ./libnss-radius
|
||||||
|
|
||||||
|
make clean
|
||||||
|
-rm -rf debian
|
||||||
|
-rm -rf patches
|
||||||
|
cp -r ../debian .
|
||||||
|
cp -r ../patches .
|
||||||
|
|
||||||
|
# Apply patch (if any)
|
||||||
|
|
||||||
|
dpkg-buildpackage -rfakeroot -b -us -uc
|
||||||
|
popd
|
||||||
|
|
||||||
|
mv $(DERIVED_TARGETS) $* $(DEST)/
|
||||||
|
|
||||||
|
$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET)
|
5
src/radius/nss/debian/README.Debian
Normal file
5
src/radius/nss/debian/README.Debian
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
libnss-radius for Debian
|
||||||
|
|
||||||
|
The Debian version of the libnss-radius package.
|
||||||
|
|
||||||
|
-- Arun Barboza <29963827+a-barboza@users.noreply.github.com> Tue, 24 Sep 2019 00:20:55 +0000
|
6
src/radius/nss/debian/changelog
Normal file
6
src/radius/nss/debian/changelog
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
libnss-radius (1.0.1-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Initial release. NSS lookups for RADIUS users with cached Management
|
||||||
|
Privilege Level (MPL) attribute.
|
||||||
|
|
||||||
|
-- Arun Barboza <29963827+a-barboza@users.noreply.github.com> Tue, 24 Sep 2019 00:20:55 +0000
|
1
src/radius/nss/debian/compat
Normal file
1
src/radius/nss/debian/compat
Normal file
@ -0,0 +1 @@
|
|||||||
|
9
|
17
src/radius/nss/debian/control
Normal file
17
src/radius/nss/debian/control
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Source: libnss-radius
|
||||||
|
Section: libs
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: Arun Barboza <29963827+a-barboza@users.noreply.github.com>
|
||||||
|
Build-Depends: debhelper (>=9)
|
||||||
|
Standards-Version: 3.9.6
|
||||||
|
Homepage: http://www.broadcom.com
|
||||||
|
|
||||||
|
Package: libnss-radius
|
||||||
|
Section: libs
|
||||||
|
Architecture: any
|
||||||
|
Multi-Arch: same
|
||||||
|
Pre-Depends: ${misc:Pre-Depends}
|
||||||
|
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||||
|
Description: NSS module for RADIUS authentication absent local account.
|
||||||
|
NSS lookups for RADIUS authenticated users using the Management Privilege
|
||||||
|
Level (MPL) cached attribute.
|
21
src/radius/nss/debian/copyright
Normal file
21
src/radius/nss/debian/copyright
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: libnss-radius
|
||||||
|
Source: http://www.broadcom.com
|
||||||
|
|
||||||
|
Files: *
|
||||||
|
Copyright: 2019 Broadcom. The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
License: Apache
|
||||||
|
Copyright 2019 Broadcom. All rights reserved.
|
||||||
|
The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
.
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
.
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
15
src/radius/nss/debian/rules
Executable file
15
src/radius/nss/debian/rules
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# You must remove unused comment lines for the released package.
|
||||||
|
#export DH_VERBOSE = 1
|
||||||
|
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
|
||||||
|
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@
|
||||||
|
|
||||||
|
#override_dh_auto_install:
|
||||||
|
# dh_auto_install -- prefix=/usr
|
||||||
|
|
||||||
|
#override_dh_install:
|
||||||
|
# dh_install --list-missing -X.pyc -X.pyo
|
2
src/radius/nss/debian/watch
Normal file
2
src/radius/nss/debian/watch
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# You must remove unused comment lines for the released package.
|
||||||
|
version=3
|
6
src/radius/nss/libnss-radius/.gitignore
vendored
Normal file
6
src/radius/nss/libnss-radius/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
cache_radius
|
||||||
|
libnss_radius.so.2
|
||||||
|
test_cache_radius
|
||||||
|
test_nss_radius
|
||||||
|
debian
|
||||||
|
patches
|
14
src/radius/nss/libnss-radius/LICENSE
Normal file
14
src/radius/nss/libnss-radius/LICENSE
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Copyright 2019 Broadcom. All rights reserved.
|
||||||
|
The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
59
src/radius/nss/libnss-radius/Makefile
Normal file
59
src/radius/nss/libnss-radius/Makefile
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Copyright 2019 Broadcom. All rights reserved.
|
||||||
|
# The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# Makefile for libnss-radius
|
||||||
|
#
|
||||||
|
|
||||||
|
TARGETS = libnss_radius.so.2 cache_radius
|
||||||
|
COMMON_INCLUDE = nss_radius_common.h
|
||||||
|
COMMON_SOURCE = nss_radius_common.c
|
||||||
|
LIBNSS_SOURCE = nss_radius.c $(COMMON_SOURCE)
|
||||||
|
CACHE_SOURCE = cache_radius.c $(COMMON_SOURCE)
|
||||||
|
|
||||||
|
# For now place the multiarch flag here
|
||||||
|
# Eventually this needs to be move to the debian packaging
|
||||||
|
#moduledir = $(prefix)/lib/x86_64-linux-gnu
|
||||||
|
moduledir = $(prefix)/lib/$(DEB_HOST_MULTIARCH)
|
||||||
|
|
||||||
|
|
||||||
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
libnss_radius.so.2: $(LIBNSS_SOURCE) $(COMMON_INCLUDE)
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -fPIC -Wall -shared -o libnss_radius.so.2 \
|
||||||
|
-Wl,-soname,libnss_radius.so.2 -Wl,--version-script=libnss_radius_vs.txt $(LIBNSS_SOURCE)
|
||||||
|
|
||||||
|
cache_radius: $(CACHE_SOURCE) $(COMMON_INCLUDE)
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o cache_radius $(CACHE_SOURCE)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -f $(TARGETS)
|
||||||
|
-rm -f test_nss_radius test_cache_radius
|
||||||
|
|
||||||
|
install: libnss_radius.so.2 cache_radius
|
||||||
|
install -m 0644 -D libnss_radius.so.2 \
|
||||||
|
$(DESTDIR)$(moduledir)/libnss_radius.so.2
|
||||||
|
install -m 0755 -D cache_radius \
|
||||||
|
$(DESTDIR)$(prefix)/usr/sbin/cache_radius
|
||||||
|
install -m 0755 -d $(DESTDIR)$(prefix)/etc/pam_radius_auth.d/
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
-rm -f $(DESTDIR)$(moduledir)/libnss_radius.so.2
|
||||||
|
-rm -f $(DESTDIR)$(prefix)/usr/sbin/cache_radius
|
||||||
|
|
||||||
|
test: test_nss_radius.c $(LIBNSS_SOURCE) $(CACHE_SOURCE) \
|
||||||
|
$(COMMON_SOURCE) $(COMMON_INCLUDE)
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -g -DTEST_RADIUS_NSS -o test_nss_radius \
|
||||||
|
$(LIBNSS_SOURCE) test_nss_radius.c
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -g -DTEST_RADIUS_NSS -o test_cache_radius \
|
||||||
|
$(CACHE_SOURCE)
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: all install clean distclean uninstall test
|
||||||
|
|
198
src/radius/nss/libnss-radius/cache_radius.c
Normal file
198
src/radius/nss/libnss-radius/cache_radius.c
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 Broadcom. All rights reserved.
|
||||||
|
The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cache_radius to be invoked after a successful pam_radius_auth.so
|
||||||
|
* module invocation as:
|
||||||
|
*
|
||||||
|
* auth [success=1 default=ignore] pam_exec.so /usr/sbin/cache_radius
|
||||||
|
*
|
||||||
|
* cache_radius -u to be invoked to clear aged unconfirmed users.
|
||||||
|
*
|
||||||
|
* auth [success=1 default=ignore] pam_exec.so /usr/sbin/cache_radius -u
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nss_radius_common.h"
|
||||||
|
|
||||||
|
static int radius_update_cache_cleanup(int status, mode_t mask, FILE * fp) {
|
||||||
|
|
||||||
|
/* Umask restore.
|
||||||
|
*/
|
||||||
|
umask(mask);
|
||||||
|
|
||||||
|
if (fp)
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int radius_update_cache( char * prog, const char * nam, int mpl) {
|
||||||
|
|
||||||
|
mode_t mask;
|
||||||
|
char filename[PATH_MAX];
|
||||||
|
int written;
|
||||||
|
struct stat sb;
|
||||||
|
FILE * fp = NULL;
|
||||||
|
|
||||||
|
/* Umask save, change.
|
||||||
|
*/
|
||||||
|
mask = umask(022);
|
||||||
|
|
||||||
|
if (((written = snprintf( filename, sizeof(filename), "%s/%s",
|
||||||
|
RADIUS_ATTRIBUTE_CACHE_DIR, nam)) + sizeof(RADIUS_ATTR_MPL) + 1)
|
||||||
|
>= sizeof(filename)) {
|
||||||
|
syslog( LOG_ERR, "%s: \"%s\": too long.", prog, filename);
|
||||||
|
return(radius_update_cache_cleanup(STATUS_EINVAL, mask, fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the directory.
|
||||||
|
*/
|
||||||
|
if ((!((stat( RADIUS_CACHE_DIR, &sb) == 0) && S_ISDIR(sb.st_mode))
|
||||||
|
&& (mkdir( RADIUS_CACHE_DIR, 0755) == -1))
|
||||||
|
|| (!((stat( RADIUS_ATTRIBUTE_CACHE_DIR, &sb) == 0) && S_ISDIR(sb.st_mode))
|
||||||
|
&& (mkdir( RADIUS_ATTRIBUTE_CACHE_DIR, 0755) == -1))
|
||||||
|
|| (!((stat( filename, &sb) == 0) && S_ISDIR(sb.st_mode))
|
||||||
|
&& (mkdir( filename, 0755) == -1))) {
|
||||||
|
syslog( LOG_ERR, "%s: \"%s\": mkdir() fails. Or ! dir errno %d",
|
||||||
|
prog, filename, errno);
|
||||||
|
return(radius_update_cache_cleanup(STATUS_ENOENT, mask, fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the file.
|
||||||
|
*/
|
||||||
|
strcat( filename, "/");
|
||||||
|
strcat( filename, RADIUS_ATTR_MPL);
|
||||||
|
|
||||||
|
if ( ((fp = fopen( filename, "w")) == NULL)
|
||||||
|
|| (fprintf(fp, "%d\n", mpl) < 0)) {
|
||||||
|
syslog( LOG_ERR,
|
||||||
|
"%s: \"%s\": fopen(): %p or fprintf() fails. errno %d", prog,
|
||||||
|
filename, (void *) fp, errno);
|
||||||
|
return(radius_update_cache_cleanup(STATUS_EPERM, mask, fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "%s: MPL %d updated for user %s", prog, mpl, nam);
|
||||||
|
|
||||||
|
return(radius_update_cache_cleanup(0, mask, fp));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int main_cleanup(int status, RADIUS_NSS_CONF_B * conf, int * pncfd) {
|
||||||
|
int my_errno = 0;
|
||||||
|
if (conf)
|
||||||
|
unparse_nss_config(conf, &my_errno, pncfd);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ac, char * av[]) {
|
||||||
|
|
||||||
|
int mpl = 1, cached_mpl = 1;
|
||||||
|
int status = 0;
|
||||||
|
int my_errno = 0;
|
||||||
|
char * user = NULL, * privilege;
|
||||||
|
RADIUS_NSS_CONF_B radius_nss_conf, * conf = & radius_nss_conf;
|
||||||
|
RADIUS_NSS_MPL * rnm;
|
||||||
|
char file_buf[RADIUS_MAX_NSS_CONF_SZ];
|
||||||
|
int ncfd = -1;
|
||||||
|
int no_clear_unconfirmed = 0;
|
||||||
|
int clear_unconfirmed_limit = 0;
|
||||||
|
int refresh_user = 0;
|
||||||
|
char buf[BUFLEN];
|
||||||
|
struct passwd pw, *result = NULL;
|
||||||
|
|
||||||
|
/* Set the logging parameters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
openlog(av[0], LOG_CONS | LOG_PID, LOG_AUTHPRIV);
|
||||||
|
|
||||||
|
/* Parse Command-Line options.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((ac == 2) && (strncmp(av[1], "-n", 3) == 0)) {
|
||||||
|
|
||||||
|
no_clear_unconfirmed = 1;
|
||||||
|
|
||||||
|
} else if (ac > 1) {
|
||||||
|
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"%s: Ignoring unknown option:\"%s\"\n", av[0], av[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read environment PAM_USER.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ((user = getenv("PAM_USER")) == NULL)
|
||||||
|
|| (user[0] == 0)) {
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"%s: Missing or bad PAM_USER in environment:\"%s\"\n",
|
||||||
|
av[0], user ? user : "(null)");
|
||||||
|
exit(main_cleanup(STATUS_ENOENT, NULL, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read environment Privilege.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((privilege = getenv("Privilege")) != NULL) {
|
||||||
|
mpl = atoi(privilege);
|
||||||
|
if (!((RADIUS_MIN_MPL <= mpl) && (mpl <= RADIUS_MAX_MPL))) {
|
||||||
|
syslog(LOG_WARNING, "%s: Invalid Management-Privilege-Level %d\n",
|
||||||
|
av[0], mpl);
|
||||||
|
mpl = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
syslog(LOG_INFO, "%s: Missing or bad Privilege in environment:\"%s\"\n",
|
||||||
|
av[0], privilege ? privilege : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_nss_config(conf, av[0], file_buf, sizeof(file_buf), &my_errno, &ncfd);
|
||||||
|
|
||||||
|
if ( (radius_lookup_cache( conf->prog, user, &cached_mpl) != 0)
|
||||||
|
|| (cached_mpl != mpl)
|
||||||
|
|| (radius_getpwnam_r(conf->prog, user, &pw, buf, sizeof(buf),&result)
|
||||||
|
!= 0)) {
|
||||||
|
|
||||||
|
radius_update_cache( conf->prog, user, mpl);
|
||||||
|
refresh_user = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->many_to_one) {
|
||||||
|
|
||||||
|
rnm = &((conf->rnm)[mpl-1]);
|
||||||
|
if (radius_getpwnam_r(conf->prog, rnm->gecos, &pw, buf, sizeof(buf),
|
||||||
|
&result) != 0) {
|
||||||
|
radius_create_user(conf, rnm->gecos, mpl, RADIUS_CONFIRMED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mpl != cached_mpl) {
|
||||||
|
|
||||||
|
syslog(LOG_WARNING, "%s: Management-Privilege-Level init/changed:"
|
||||||
|
" %d --> %d\n", conf->prog, cached_mpl, mpl);
|
||||||
|
fprintf(stdout, "Management-Privilege-Level inited or changed.\n");
|
||||||
|
fprintf(stdout, "Please login again.\n");
|
||||||
|
exit(main_cleanup(STATUS_EPERM, conf, &ncfd));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (!(conf->many_to_one) && refresh_user) {
|
||||||
|
|
||||||
|
radius_update_user( conf, user, mpl);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!no_clear_unconfirmed && (conf->many_to_one == 0)) {
|
||||||
|
clear_unconfirmed_limit = conf->unconfirmed_clear_limit;
|
||||||
|
while(radius_clear_unconfirmed_users(conf) == 0) {
|
||||||
|
if (clear_unconfirmed_limit-- <= 0) {
|
||||||
|
syslog(LOG_INFO, "%s: Clear unconfirmed limit %d reached:",
|
||||||
|
conf->prog, conf->unconfirmed_clear_limit);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(main_cleanup(0, conf, &ncfd));
|
||||||
|
}
|
4
src/radius/nss/libnss-radius/libnss_radius_vs.txt
Normal file
4
src/radius/nss/libnss-radius/libnss_radius_vs.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
global: _nss_radius_getpwnam_r;
|
||||||
|
local: *;
|
||||||
|
};
|
84
src/radius/nss/libnss-radius/nss_radius.c
Normal file
84
src/radius/nss/libnss-radius/nss_radius.c
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 Broadcom. All rights reserved.
|
||||||
|
The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* plugin implements getpwnam_r for NSS for RADIUS cached MPL(Management
|
||||||
|
* Privilege Attribute).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "nss_radius_common.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NSS entry point for getpwnam().
|
||||||
|
*/
|
||||||
|
enum nss_status _nss_radius_getpwnam_r( const char * nam, struct passwd * pwd,
|
||||||
|
char * buf, size_t buflen, int * errnop) {
|
||||||
|
|
||||||
|
enum nss_status status = NSS_STATUS_NOTFOUND;
|
||||||
|
int mpl = 1;
|
||||||
|
int ncfd = -1;
|
||||||
|
RADIUS_NSS_CONF_B radius_nss_conf, * conf = &(radius_nss_conf);
|
||||||
|
RADIUS_NSS_MPL * rnm;
|
||||||
|
char file_buf[RADIUS_MAX_NSS_CONF_SZ];
|
||||||
|
char buffer[BUFLEN];
|
||||||
|
struct passwd pw, *res = NULL;
|
||||||
|
char * prog = "nss";
|
||||||
|
|
||||||
|
/* Ignore filename completion.
|
||||||
|
*/
|
||||||
|
if (!nam || !strcmp(nam, "*") || !pwd || !buf || (buflen == 0))
|
||||||
|
return NSS_STATUS_NOTFOUND;
|
||||||
|
|
||||||
|
parse_nss_config(conf, prog, file_buf, sizeof(file_buf), errnop, &ncfd);
|
||||||
|
|
||||||
|
if (radius_lookup_cache(prog, nam, &mpl) == 0) {
|
||||||
|
|
||||||
|
/* The MPL exists for this user in the cache.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (conf->debug)
|
||||||
|
syslog( LOG_DEBUG, "%s: nam: %s", prog, nam);
|
||||||
|
|
||||||
|
rnm = &((conf->rnm)[mpl-1]);
|
||||||
|
if (conf->many_to_one) {
|
||||||
|
radius_getpwnam_r(prog, rnm->gecos, &pw, buffer, sizeof(buffer),
|
||||||
|
&res);
|
||||||
|
} else if (conf->allow_anonymous) {
|
||||||
|
radius_create_user(conf, nam, mpl, RADIUS_CONFIRMED);
|
||||||
|
radius_getpwnam_r(prog, nam, &pw, buffer, sizeof(buffer), &res);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (conf->allow_anonymous && is_sshd_lookup(conf, nam)) {
|
||||||
|
|
||||||
|
/* Could be an sshd doing a getpwnam() before pam_authenticate().
|
||||||
|
*/
|
||||||
|
|
||||||
|
rnm = &((conf->rnm)[mpl-1]);
|
||||||
|
if (conf->many_to_one) {
|
||||||
|
if (radius_getpwnam_r(prog, rnm->gecos, &pw, buffer, sizeof(buffer),
|
||||||
|
&res) != 0) {
|
||||||
|
radius_create_user(conf, rnm->gecos, mpl, RADIUS_CONFIRMED);
|
||||||
|
radius_getpwnam_r(prog, rnm->gecos, &pw, buffer, sizeof(buffer),
|
||||||
|
&res);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
radius_create_user(conf, nam, mpl, RADIUS_UNCONFIRMED);
|
||||||
|
radius_getpwnam_r(prog, nam, &pw, buffer, sizeof(buffer), &res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the pwd
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
status = NSS_STATUS_SUCCESS;
|
||||||
|
radius_copy_pw(conf, res, nam, pwd, buf, buflen, errnop);
|
||||||
|
}
|
||||||
|
|
||||||
|
unparse_nss_config(conf, errnop, &ncfd);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
780
src/radius/nss/libnss-radius/nss_radius_common.c
Normal file
780
src/radius/nss/libnss-radius/nss_radius_common.c
Normal file
@ -0,0 +1,780 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 Broadcom. All rights reserved.
|
||||||
|
The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common code for NSS for RADIUS cached MPL(Management Privilege Attribute).
|
||||||
|
* Used by both NSS module(uses the cache) and PAM module(updates the cache)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <nss.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <regex.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "nss_radius_common.h"
|
||||||
|
|
||||||
|
static void dump_rnm(int mpl, RADIUS_NSS_MPL * rnm, char * msg) {
|
||||||
|
|
||||||
|
syslog( LOG_DEBUG, "dump_rnm: %s:"
|
||||||
|
"mpl %d gid %d groups \"%s\" gecos \"%s\" shell \"%s\"",
|
||||||
|
(msg ? msg : ""), mpl, rnm->gid, rnm->groups, rnm->gecos, rnm->shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * parse_line(RADIUS_NSS_CONF_B * conf, char * file_buf,
|
||||||
|
char ** pscanpos, int * premain) {
|
||||||
|
|
||||||
|
char * line = NULL;
|
||||||
|
int skipline = 0;
|
||||||
|
|
||||||
|
for( ; (*premain); (*pscanpos)++, (*premain)--) {
|
||||||
|
if (skipline) {
|
||||||
|
if ( ((**pscanpos) == '\n')
|
||||||
|
|| ((**pscanpos) == '\r')
|
||||||
|
|| ((**pscanpos) == '\f')) {
|
||||||
|
skipline = 0;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (line == NULL) {
|
||||||
|
if (isspace(**pscanpos)) {
|
||||||
|
continue;
|
||||||
|
} else if ((**pscanpos) == '#') {
|
||||||
|
skipline = 1;
|
||||||
|
} else {
|
||||||
|
line = *pscanpos;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if ( ((**pscanpos) == '\n')
|
||||||
|
|| ((**pscanpos) == '\r')
|
||||||
|
|| ((**pscanpos) == '\f')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line) {
|
||||||
|
*((*pscanpos)++) = 0;
|
||||||
|
if (*premain)
|
||||||
|
(*premain)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->trace)
|
||||||
|
syslog(LOG_DEBUG, "parse_line: \"%s\"\n", line ? line : "");
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * parse_token(RADIUS_NSS_CONF_B * conf, char ** pbufpos,
|
||||||
|
int * premain) {
|
||||||
|
char * token = NULL;
|
||||||
|
|
||||||
|
for( token = *pbufpos;
|
||||||
|
(*premain) && (**pbufpos) && ((**pbufpos) != ';') ;
|
||||||
|
(*pbufpos)++, (*premain)--)
|
||||||
|
; /* Empty Body */
|
||||||
|
|
||||||
|
if (*premain) {
|
||||||
|
*((*pbufpos)++) = 0;
|
||||||
|
(*premain)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->trace)
|
||||||
|
syslog(LOG_DEBUG, "parse_token: \"%s\"\n", token ? token : "");
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_user(RADIUS_NSS_CONF_B * conf, char * line) {
|
||||||
|
RADIUS_NSS_MPL parse_rnm;
|
||||||
|
char * token, * bufpos;
|
||||||
|
int mpl = 0;
|
||||||
|
int ret = 0, remain;
|
||||||
|
|
||||||
|
bufpos = line;
|
||||||
|
remain = strlen(line);
|
||||||
|
memset((char *) &parse_rnm, 0, sizeof(parse_rnm));
|
||||||
|
|
||||||
|
while (remain && (token = parse_token(conf, &bufpos, &remain))) {
|
||||||
|
if (strncmp(token, "user_priv=", 10) == 0) {
|
||||||
|
mpl = atoi(&token[10]);
|
||||||
|
} else if (strncmp(token, "group=", 6) == 0) {
|
||||||
|
parse_rnm.groups = &(token[6]);
|
||||||
|
} else if (strncmp(token, "pw_info=", 8) == 0) {
|
||||||
|
parse_rnm.gecos = &(token[8]);
|
||||||
|
} else if (strncmp(token, "uid=", 4) == 0) {
|
||||||
|
syslog( LOG_WARNING, "%s: Ignoring \"%s\"."
|
||||||
|
" Using system assigned User ID", RADIUS_NSS_CONF, token);
|
||||||
|
} else if (strncmp(token, "gid=", 4) == 0) {
|
||||||
|
parse_rnm.gid = atol(&(token[4]));
|
||||||
|
} else if (strncmp(token, "dir=", 4) == 0) {
|
||||||
|
syslog( LOG_WARNING, "%s: Ignoring \"%s\"."
|
||||||
|
" Using system assigned home directory",
|
||||||
|
RADIUS_NSS_CONF, token);
|
||||||
|
} else if (strncmp(token, "shell=", 6) == 0) {
|
||||||
|
parse_rnm.shell = &(token[6]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->trace)
|
||||||
|
dump_rnm(mpl, &parse_rnm, "parse");
|
||||||
|
|
||||||
|
if ( ((RADIUS_MIN_MPL > mpl) || (mpl > RADIUS_MAX_MPL))
|
||||||
|
|| (parse_rnm.gid == 0)
|
||||||
|
|| (parse_rnm.groups == NULL)
|
||||||
|
|| (parse_rnm.gecos == NULL)
|
||||||
|
|| (parse_rnm.shell == NULL)) {
|
||||||
|
|
||||||
|
syslog( LOG_WARNING, "%s: Bad user_priv line \"%s\"", RADIUS_NSS_CONF,
|
||||||
|
line);
|
||||||
|
ret = 1;
|
||||||
|
} else {
|
||||||
|
(conf->rnm)[mpl-1] = parse_rnm;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_rnm(RADIUS_NSS_CONF_B * conf) {
|
||||||
|
|
||||||
|
RADIUS_NSS_MPL * rnm = conf->rnm;
|
||||||
|
|
||||||
|
/* Set rnm[0,max_mpl-1].
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset((char *) rnm, 0, sizeof(conf->rnm));
|
||||||
|
|
||||||
|
rnm[0].gid = 999;
|
||||||
|
rnm[0].groups = "docker";
|
||||||
|
rnm[0].gecos = "remote_user";
|
||||||
|
rnm[0].shell = "/usr/bin/sonic-launch-shell";
|
||||||
|
rnm[RADIUS_MAX_MPL-1].gid = 1000;
|
||||||
|
rnm[RADIUS_MAX_MPL-1].groups = "admin,sudo,docker";
|
||||||
|
rnm[RADIUS_MAX_MPL-1].gecos = "remote_user_su";
|
||||||
|
rnm[RADIUS_MAX_MPL-1].shell = "/usr/bin/sonic-launch-shell";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_nss_config(RADIUS_NSS_CONF_B * conf, char * prog,
|
||||||
|
char * file_buf, int file_buf_sz, int * errnop, int * plockfd) {
|
||||||
|
|
||||||
|
/* Slurp the whole file.
|
||||||
|
*/
|
||||||
|
int ncfd = -1;
|
||||||
|
int ret = 0;
|
||||||
|
int i = 0, remain;
|
||||||
|
struct stat sb;
|
||||||
|
char errbuf[128];
|
||||||
|
int flags;
|
||||||
|
char * scanpos, * line;
|
||||||
|
int use_default_rnm = 1, bad_rnm = 0;
|
||||||
|
int unconfirmed_disallow = 0;
|
||||||
|
|
||||||
|
memset((char *)conf, 0, sizeof(*conf));
|
||||||
|
conf->prog = prog;
|
||||||
|
conf->allow_anonymous = 1;
|
||||||
|
conf->unconfirmed_ageout = UNCONFIRMED_AGEOUT_DEFAULT;
|
||||||
|
conf->unconfirmed_clear_limit = UNCONFIRMED_CLEAR_LIMIT_DEFAULT;
|
||||||
|
|
||||||
|
/* Read the file.
|
||||||
|
*/
|
||||||
|
if (((ncfd = open(RADIUS_NSS_CONF, O_RDONLY)) == -1)
|
||||||
|
|| (fstat(ncfd, &sb) == -1)
|
||||||
|
|| (((flags = fcntl(ncfd, F_GETFL, 0)) == -1) && ((flags = 0) != 0))
|
||||||
|
|| (fcntl(ncfd, F_SETFL, flags | O_NONBLOCK) == -1)) {
|
||||||
|
|
||||||
|
if (errnop)
|
||||||
|
*errnop = errno;
|
||||||
|
ret = 1;
|
||||||
|
errbuf[0] = 0; strerror_r(errno, errbuf, sizeof(errbuf));
|
||||||
|
syslog( LOG_WARNING, "%s: %s", prog, errbuf);
|
||||||
|
goto parse_nss_config_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The maximum file size is 1 less than the buffer, to allow space for
|
||||||
|
* a NULL byte in the case where the last line has no \n, \r, \l char.
|
||||||
|
* (which could have been substituted with a NULL).
|
||||||
|
*/
|
||||||
|
if (sb.st_size >= file_buf_sz) {
|
||||||
|
syslog( LOG_WARNING, "%s: size greater than %d. Ignoring",
|
||||||
|
prog, file_buf_sz - 1);
|
||||||
|
goto parse_nss_config_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i = read(ncfd, file_buf, file_buf_sz)) != sb.st_size) {
|
||||||
|
syslog( LOG_WARNING, "%s: read %d of %ld. Ignoring", prog,
|
||||||
|
i, sb.st_size);
|
||||||
|
goto parse_nss_config_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse each line from file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
scanpos = file_buf;
|
||||||
|
remain = sb.st_size;
|
||||||
|
while((line = parse_line(conf, file_buf, &scanpos, &remain)) != NULL) {
|
||||||
|
|
||||||
|
if (strncmp(line, "debug=", 6) == 0) {
|
||||||
|
|
||||||
|
if (strncmp(&(line[6]), "on", 2) == 0) {
|
||||||
|
|
||||||
|
/* Handle "debug".
|
||||||
|
*/
|
||||||
|
|
||||||
|
conf->debug = 1;
|
||||||
|
|
||||||
|
} else if (strncmp(&(line[6]), "trace", 5) == 0) {
|
||||||
|
|
||||||
|
conf->debug = 1;
|
||||||
|
conf->trace = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (strncmp(line, "user_priv=", 10) == 0) {
|
||||||
|
|
||||||
|
/* Handle "user_priv"
|
||||||
|
*/
|
||||||
|
|
||||||
|
use_default_rnm = 0;
|
||||||
|
if (parse_user(conf, line)) {
|
||||||
|
bad_rnm = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (strncmp(line, "many_to_one=", 12) == 0) {
|
||||||
|
|
||||||
|
/* Handle "many_to_one"
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((strncmp(&(line[12]), "y", 2) == 0) ||
|
||||||
|
(strncmp(&(line[12]), "ye", 3) == 0) ||
|
||||||
|
(strncmp(&(line[12]), "yes", 4) == 0)) {
|
||||||
|
|
||||||
|
conf->many_to_one = 1;
|
||||||
|
|
||||||
|
} else if (strncmp(&(line[12]), "a", 1) == 0) {
|
||||||
|
|
||||||
|
conf->many_to_one = 0;
|
||||||
|
syslog( LOG_WARNING, "%s: a(nonymous) is same as n(o) option:"
|
||||||
|
" \"%s\"", prog, line);
|
||||||
|
|
||||||
|
} else if ((strncmp(&(line[12]), "n", 2) == 0) ||
|
||||||
|
(strncmp(&(line[12]), "no", 3) == 0)) {
|
||||||
|
|
||||||
|
conf->many_to_one = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
syslog( LOG_WARNING, "%s: Ignorning \"%s\"", prog, line);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (strncmp(line, "unconfirmed_regexp=", 19) == 0) {
|
||||||
|
|
||||||
|
conf->unconfirmed_regexp = &(line[19]);
|
||||||
|
|
||||||
|
} else if (strncmp(line, "unconfirmed_ageout=", 19) == 0) {
|
||||||
|
|
||||||
|
conf->unconfirmed_ageout = atoi(&(line[19]));
|
||||||
|
|
||||||
|
} else if (strncmp(line, "unconfirmed_disallow=", 21) == 0) {
|
||||||
|
|
||||||
|
if ((strncmp(&(line[21]), "y", 2) == 0) ||
|
||||||
|
(strncmp(&(line[21]), "ye", 3) == 0) ||
|
||||||
|
(strncmp(&(line[21]), "yes", 4) == 0)) {
|
||||||
|
|
||||||
|
unconfirmed_disallow = 1;
|
||||||
|
|
||||||
|
} else if ((strncmp(&(line[21]), "n", 2) == 0) ||
|
||||||
|
(strncmp(&(line[21]), "no", 3) == 0)) {
|
||||||
|
|
||||||
|
unconfirmed_disallow = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
syslog( LOG_WARNING, "%s: Ignorning \"%s\"", prog, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
syslog( LOG_WARNING, "%s: Ignoring \"%s\"", prog, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unconfirmed_disallow) {
|
||||||
|
|
||||||
|
conf->allow_anonymous = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse_nss_config_exit:
|
||||||
|
|
||||||
|
if (ncfd != -1) {
|
||||||
|
|
||||||
|
if (flock(ncfd, LOCK_EX|LOCK_NB) == 0) {
|
||||||
|
if (conf->debug)
|
||||||
|
syslog( LOG_DEBUG, "%s: %d: Unconfirmed: lock success",
|
||||||
|
prog, (int) getpid());
|
||||||
|
} else {
|
||||||
|
conf->allow_anonymous = 0;
|
||||||
|
if (conf->debug)
|
||||||
|
syslog( LOG_DEBUG, "%s: %d: Unconfirmed: locked out",
|
||||||
|
prog, (int) getpid());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plockfd) {
|
||||||
|
*plockfd = ncfd;
|
||||||
|
} else {
|
||||||
|
close(ncfd); /* This should release the lock, if we placed one */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Fix up rnm.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (use_default_rnm || bad_rnm)
|
||||||
|
init_rnm(conf);
|
||||||
|
|
||||||
|
for ( i = 1; i < RADIUS_MAX_MPL; i++) {
|
||||||
|
if ((conf->rnm)[i].gecos == NULL) {
|
||||||
|
(conf->rnm)[i] = (conf->rnm)[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Releases any memory.
|
||||||
|
* Closes any fds.
|
||||||
|
*/
|
||||||
|
int unparse_nss_config(RADIUS_NSS_CONF_B * conf, int * errnop, int * plockfd) {
|
||||||
|
|
||||||
|
/* If the caller had a lock in parse_nss_config(),
|
||||||
|
* we should now release that lock.
|
||||||
|
*/
|
||||||
|
if (plockfd && (*plockfd != -1)) {
|
||||||
|
if (flock(*plockfd, LOCK_UN|LOCK_NB) == 0) {
|
||||||
|
if (conf->debug)
|
||||||
|
syslog( LOG_DEBUG, "%s: %d: Unconfirmed: unlock success",
|
||||||
|
conf->prog, (int) getpid());
|
||||||
|
} else {
|
||||||
|
syslog( LOG_ERR, "%s: %d: Unconfirme: unlock fail",
|
||||||
|
conf->prog, (int) getpid());
|
||||||
|
}
|
||||||
|
close(*plockfd);
|
||||||
|
*plockfd = -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int invoke_popen(RADIUS_NSS_CONF_B * conf, char * cmd) {
|
||||||
|
FILE * fp;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
if (conf->debug)
|
||||||
|
syslog(LOG_DEBUG, "%s:%s", conf->prog, cmd);
|
||||||
|
|
||||||
|
if (((fp = popen(cmd, "r")) == NULL) || (pclose(fp) == -1)) {
|
||||||
|
syslog(LOG_ERR, "%s: %s: popen()/pclose() failed %p, errno=%d",
|
||||||
|
conf->prog, cmd, fp, errno);
|
||||||
|
status = errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int radius_getpwnam_r_cleanup(int status, FILE * fp) {
|
||||||
|
if (fp)
|
||||||
|
fclose(fp);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_getpwnam_r(char * prog, const char * name,
|
||||||
|
struct passwd * pwd, char * buf, int buflen, struct passwd ** result) {
|
||||||
|
|
||||||
|
FILE *fp;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if ((fp = fopen(ETC_PASSWD, "r")) == NULL) {
|
||||||
|
syslog(LOG_ERR, "%s: fopen(\"/etc/passwd\") failed\n", prog);
|
||||||
|
return radius_getpwnam_r_cleanup(STATUS_ENOENT, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
while((status = fgetpwent_r(fp, pwd, buf, buflen, result)) == 0) {
|
||||||
|
if ( (*result)
|
||||||
|
&& (*result)->pw_name
|
||||||
|
&& (strcmp((*result)->pw_name, name) == 0)) {
|
||||||
|
return radius_getpwnam_r_cleanup(status, fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "%s: User %s not found in local db: %d\n", prog, name,
|
||||||
|
status);
|
||||||
|
|
||||||
|
return radius_getpwnam_r_cleanup(status, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int radius_update_user_cleanup(int status) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_update_user(RADIUS_NSS_CONF_B * conf, const char * user, int mpl) {
|
||||||
|
|
||||||
|
char buf[BUFLEN];
|
||||||
|
char usermod[4096];
|
||||||
|
struct passwd pw, *result = NULL;
|
||||||
|
RADIUS_NSS_MPL * rnm = NULL;
|
||||||
|
int written = 0;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/* Verify uid is not in the reserved range (<=1000).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((status = radius_getpwnam_r(conf->prog, user, &pw, buf, sizeof(buf),
|
||||||
|
&result)) != 0) {
|
||||||
|
|
||||||
|
/* /bin/login does NSS after PAM.
|
||||||
|
*/
|
||||||
|
status = radius_create_user(conf, user, mpl, RADIUS_CONFIRMED);
|
||||||
|
return radius_update_user_cleanup(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result->pw_uid <= 1000) {
|
||||||
|
syslog(LOG_INFO, "%s: Not changing \"%s\", uid(%d) <= 1000",
|
||||||
|
conf->prog, user, result->pw_uid);
|
||||||
|
return radius_update_user_cleanup(STATUS_EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "%s: Adjusting Supplementary Groups for \"%s\"",
|
||||||
|
conf->prog, user);
|
||||||
|
|
||||||
|
rnm = &((conf->rnm)[mpl-1]);
|
||||||
|
|
||||||
|
if (conf->trace)
|
||||||
|
dump_rnm(mpl, rnm, "update");
|
||||||
|
|
||||||
|
written = snprintf(usermod, sizeof(usermod),
|
||||||
|
"%s -G %s -c \"%s\" \"%s\"", USERMOD, rnm->groups, user, user);
|
||||||
|
|
||||||
|
if (written >= sizeof(usermod)) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"%s: truncated usermod cmd. Skipping:\"%s\"\n", conf->prog, usermod);
|
||||||
|
return radius_update_user_cleanup(STATUS_E2BIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
return radius_update_user_cleanup(invoke_popen(conf, usermod));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int radius_create_user_cleanup(int status) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_create_user(RADIUS_NSS_CONF_B * conf, const char * user, int mpl,
|
||||||
|
int unconfirmed) {
|
||||||
|
|
||||||
|
char buf[BUFLEN];
|
||||||
|
char useradd[4096];
|
||||||
|
RADIUS_NSS_MPL * rnm = &((conf->rnm)[mpl-1]);
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
if (conf->trace)
|
||||||
|
dump_rnm(mpl, rnm, "create");
|
||||||
|
|
||||||
|
|
||||||
|
if (conf->many_to_one) {
|
||||||
|
|
||||||
|
written = snprintf(useradd, sizeof(useradd),
|
||||||
|
"%s -g %d -G %s -c \"%s\" -m -s %s \"%s\"",
|
||||||
|
USERADD, rnm->gid, rnm->groups, rnm->gecos, rnm->shell, user);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "Unconfirmed-%ld", time(NULL));
|
||||||
|
written = snprintf(useradd, sizeof(useradd),
|
||||||
|
"%s -U -G %s -c \"%s\" -d \"/home/%s\" -m -s %s \"%s\"",
|
||||||
|
USERADD, rnm->groups, unconfirmed ? buf : user, user,
|
||||||
|
rnm->shell, user);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (written >= sizeof(useradd)) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"%s: truncated useradd cmd. Skipping:\"%s\"\n", conf->prog, useradd);
|
||||||
|
return radius_create_user_cleanup(STATUS_E2BIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "%s: Creating user \"%s\"", conf->prog, user);
|
||||||
|
|
||||||
|
return radius_create_user_cleanup(invoke_popen(conf, useradd));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int radius_delete_user_cleanup(int status) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_delete_user(RADIUS_NSS_CONF_B * conf, const char * user) {
|
||||||
|
|
||||||
|
char buf[BUFLEN];
|
||||||
|
char userdel[4096];
|
||||||
|
int written = 0;
|
||||||
|
|
||||||
|
written = snprintf(userdel, sizeof(userdel), "%s -r \"%s\"", USERDEL, user);
|
||||||
|
|
||||||
|
if (written >= sizeof(userdel)) {
|
||||||
|
syslog(LOG_ERR,
|
||||||
|
"%s: truncated userdel cmd. Skipping:\"%s\"\n", conf->prog, userdel);
|
||||||
|
return radius_delete_user_cleanup(STATUS_E2BIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "%s: Deleting user \"%s\"", conf->prog, user);
|
||||||
|
|
||||||
|
return radius_delete_user_cleanup(invoke_popen(conf, userdel));
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_clear_unconfirmed_users_cleanup(int status, FILE * fp) {
|
||||||
|
if (fp)
|
||||||
|
fclose(fp);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_clear_unconfirmed_users(RADIUS_NSS_CONF_B * conf)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int status;
|
||||||
|
time_t ts, curr = time(NULL);
|
||||||
|
struct passwd pw, * pwd = & pw, * result = NULL;
|
||||||
|
char buf[BUFLEN];
|
||||||
|
|
||||||
|
if ((fp = fopen(ETC_PASSWD, "r")) == NULL) {
|
||||||
|
syslog(LOG_ERR, "%s: fopen(\"/etc/passwd\") failed\n", conf->prog);
|
||||||
|
return radius_clear_unconfirmed_users_cleanup(STATUS_ENOENT, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
while((status = fgetpwent_r(fp, pwd, buf, sizeof(buf), &result)) == 0) {
|
||||||
|
if ( (result)
|
||||||
|
&& (strncmp((result)->pw_gecos, "Unconfirmed-", 12) == 0)
|
||||||
|
&& (ts = atoi(&(((result)->pw_gecos)[12])))
|
||||||
|
&& ((curr - ts) >= conf->unconfirmed_ageout)) {
|
||||||
|
|
||||||
|
syslog(LOG_INFO, "%s: Deleting unconfirmed user \"%s\"",
|
||||||
|
conf->prog, (result)->pw_name);
|
||||||
|
|
||||||
|
return radius_clear_unconfirmed_users_cleanup(
|
||||||
|
radius_delete_user(conf, (result)->pw_name), fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return radius_clear_unconfirmed_users_cleanup(STATUS_ESRCH, fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int radius_lookup_cache_cleanup( int status, int rafd) {
|
||||||
|
if (rafd != -1)
|
||||||
|
close(rafd);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_lookup_cache( char * prog, const char * nam, int * pmpl) {
|
||||||
|
int rafd = -1;
|
||||||
|
int i;
|
||||||
|
char cache_filename[PATH_MAX];
|
||||||
|
char file_buf[10];
|
||||||
|
struct stat sb;
|
||||||
|
int flags;
|
||||||
|
int written;
|
||||||
|
int mpl;
|
||||||
|
|
||||||
|
*pmpl = RADIUS_MIN_MPL;
|
||||||
|
|
||||||
|
if ((written = snprintf(cache_filename, sizeof(cache_filename), "%s/%s/%s",
|
||||||
|
RADIUS_ATTRIBUTE_CACHE_DIR, nam, RADIUS_ATTR_MPL)
|
||||||
|
>= sizeof(cache_filename))) {
|
||||||
|
syslog( LOG_ERR, "%s: \"%s\": too long.", prog, cache_filename);
|
||||||
|
return radius_lookup_cache_cleanup(STATUS_E2BIG, rafd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the user's cache exists
|
||||||
|
*/
|
||||||
|
if (((rafd = open(cache_filename, O_RDONLY)) == -1)
|
||||||
|
|| (fstat(rafd, &sb) == -1)
|
||||||
|
|| (((flags = fcntl(rafd, F_GETFL, 0)) == -1) && ((flags = 0) != 0))
|
||||||
|
|| (fcntl(rafd, F_SETFL, flags | O_NONBLOCK) == -1)) {
|
||||||
|
syslog( LOG_INFO, "%s: \"%s\": Absent.", prog, cache_filename);
|
||||||
|
return radius_lookup_cache_cleanup(STATUS_ENOENT, rafd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the privilege attribute file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (sb.st_size >= sizeof(file_buf)) {
|
||||||
|
syslog( LOG_WARNING, "%s: size %ld greater than %ld. Ignoring",
|
||||||
|
cache_filename, sb.st_size, sizeof(file_buf)-1);
|
||||||
|
return radius_lookup_cache_cleanup(STATUS_EFBIG, rafd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i = read(rafd, file_buf, sizeof(file_buf))) != sb.st_size) {
|
||||||
|
syslog( LOG_WARNING, "%s: read %d of %ld. Ignoring", prog,
|
||||||
|
i, sb.st_size);
|
||||||
|
return radius_lookup_cache_cleanup(STATUS_EIO, rafd);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_buf[sb.st_size] = 0;
|
||||||
|
mpl = atoi(file_buf);
|
||||||
|
|
||||||
|
if (((RADIUS_MIN_MPL <= mpl) && (mpl <= RADIUS_MAX_MPL)))
|
||||||
|
*pmpl = mpl;
|
||||||
|
|
||||||
|
return radius_lookup_cache_cleanup(0, rafd);
|
||||||
|
}
|
||||||
|
|
||||||
|
int radius_copy_pw( RADIUS_NSS_CONF_B * conf, struct passwd * res,
|
||||||
|
const char * nam, struct passwd * pwd,
|
||||||
|
char * buffer, size_t buflen, int * errnop) {
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
size_t namlen, gecoslen, dirlen, shelllen;
|
||||||
|
|
||||||
|
size_t totallen = (namlen = strlen(res->pw_name)) + 1
|
||||||
|
+ (gecoslen = strlen(res->pw_gecos)) + 1
|
||||||
|
+ (dirlen = strlen(res->pw_dir)) + 1
|
||||||
|
+ (shelllen = strlen(res->pw_shell)) + 1
|
||||||
|
+ 1 + 1;
|
||||||
|
|
||||||
|
if (totallen > buflen) {
|
||||||
|
if (errnop)
|
||||||
|
*errnop = ERANGE;
|
||||||
|
ret = 1;
|
||||||
|
if (conf->debug)
|
||||||
|
syslog(LOG_INFO, "(%s->%s): %s: getpwnam_r ERANGE %ld < %ld\n",
|
||||||
|
conf->prog, nam, res->pw_name, buflen, totallen);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy( buffer, res->pw_name, namlen + 1);
|
||||||
|
pwd->pw_name = buffer;
|
||||||
|
buffer += (namlen + 1);
|
||||||
|
|
||||||
|
memcpy( buffer, "*", 1 + 1);
|
||||||
|
pwd->pw_passwd = buffer;
|
||||||
|
buffer += (1 + 1);
|
||||||
|
|
||||||
|
pwd->pw_uid = res->pw_uid;
|
||||||
|
|
||||||
|
pwd->pw_gid = res->pw_gid;
|
||||||
|
|
||||||
|
memcpy( buffer, res->pw_gecos, gecoslen + 1);
|
||||||
|
pwd->pw_gecos = buffer;
|
||||||
|
buffer += (gecoslen + 1);
|
||||||
|
|
||||||
|
memcpy( buffer, res->pw_dir, dirlen + 1);
|
||||||
|
pwd->pw_dir = buffer;
|
||||||
|
buffer += (dirlen + 1);
|
||||||
|
|
||||||
|
memcpy( buffer, res->pw_shell, shelllen + 1);
|
||||||
|
pwd->pw_shell = buffer;
|
||||||
|
buffer += (shelllen + 1);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int is_sshd_lookup_exit(int status, int fd, regex_t * re) {
|
||||||
|
if (fd != -1)
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (re)
|
||||||
|
regfree(re);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int is_sshd_lookup(RADIUS_NSS_CONF_B * conf, const char * name) {
|
||||||
|
pid_t pid = getpid();
|
||||||
|
int fd, i;
|
||||||
|
regex_t regex, * re = NULL;
|
||||||
|
int reg_ret;
|
||||||
|
|
||||||
|
|
||||||
|
#define PROC_FILENAME_LEN 128
|
||||||
|
#define CMDLINE_SZ 128
|
||||||
|
|
||||||
|
char proc_file[PROC_FILENAME_LEN];
|
||||||
|
char cmdline[CMDLINE_SZ], * colon;
|
||||||
|
char expected[CMDLINE_SZ];
|
||||||
|
char accepted[CMDLINE_SZ];
|
||||||
|
char errbuf[CMDLINE_SZ];
|
||||||
|
|
||||||
|
snprintf(proc_file, sizeof(proc_file), "/proc/%ld/cmdline", (long) pid);
|
||||||
|
snprintf(expected, sizeof(expected), ": %s [priv]", name);
|
||||||
|
snprintf(accepted, sizeof(accepted), ": [accepted]");
|
||||||
|
|
||||||
|
if ((fd = open(proc_file, O_RDONLY)) == -1) {
|
||||||
|
|
||||||
|
syslog( LOG_WARNING, "%s: open(%s) failed: errno %d",
|
||||||
|
conf->prog, proc_file, errno);
|
||||||
|
return is_sshd_lookup_exit(0, fd, re);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i = read(fd, cmdline, sizeof(cmdline)-1)) <= 0) {
|
||||||
|
syslog( LOG_WARNING, "%s: %s: read(%d) failed: errno %d. Ignoring",
|
||||||
|
conf->prog, proc_file, fd, errno);
|
||||||
|
return is_sshd_lookup_exit(0, fd, re);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->unconfirmed_regexp) {
|
||||||
|
|
||||||
|
if ((reg_ret = regcomp(®ex, conf->unconfirmed_regexp,
|
||||||
|
REG_EXTENDED|REG_NOSUB))) {
|
||||||
|
|
||||||
|
errbuf[0] = 0;
|
||||||
|
regerror(reg_ret, ®ex, errbuf, sizeof(errbuf));
|
||||||
|
syslog( LOG_ERR, "%s: %s: regcomp() failed: %s", conf->prog,
|
||||||
|
conf->unconfirmed_regexp, errbuf);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
re = ®ex;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (re) {
|
||||||
|
|
||||||
|
if (!(reg_ret = regexec(re, cmdline, 0, NULL, 0))) {
|
||||||
|
syslog( LOG_INFO, "%s: %s: Lookup %s", conf->prog, cmdline, name);
|
||||||
|
return is_sshd_lookup_exit(1, fd, re);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
cmdline[i] = 0;
|
||||||
|
colon = strchr(cmdline, ':');
|
||||||
|
|
||||||
|
if (colon && ((0 == strncmp(expected, colon, sizeof(expected) - 1)) ||
|
||||||
|
(0 == strncmp(accepted, colon, sizeof(accepted) - 1)))) {
|
||||||
|
syslog( LOG_INFO, "%s: %s: Lookup %s", conf->prog, cmdline, name);
|
||||||
|
return is_sshd_lookup_exit(1, fd, re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conf->debug)
|
||||||
|
syslog( LOG_DEBUG, "%s: %s: Non sshd Lookup %s",
|
||||||
|
conf->prog, cmdline, name);
|
||||||
|
|
||||||
|
return is_sshd_lookup_exit(0, fd, re);
|
||||||
|
}
|
||||||
|
|
132
src/radius/nss/libnss-radius/nss_radius_common.h
Normal file
132
src/radius/nss/libnss-radius/nss_radius_common.h
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Broadcom. All rights reserved.
|
||||||
|
The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nss_radius_common.h
|
||||||
|
*
|
||||||
|
* Common code for NSS for RADIUS cached MPL(Management Privilege Attribute).
|
||||||
|
* Used by both NSS module(uses the cache) and PAM module(updates the cache)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <nss.h>
|
||||||
|
|
||||||
|
#define RADIUS_MAX_MPL (15)
|
||||||
|
#define RADIUS_MIN_MPL (1)
|
||||||
|
|
||||||
|
#define RADIUS_NSS_CONF "/etc/radius_nss.conf"
|
||||||
|
#define RADIUS_MAX_NSS_CONF_SZ 2048
|
||||||
|
|
||||||
|
#define RADIUS_ATTRIBUTE_CACHE_DIR "/var/cache/radius/user"
|
||||||
|
#define RADIUS_CACHE_DIR "/var/cache/radius"
|
||||||
|
#define RADIUS_ATTR_MPL "Management-Privilege-Level"
|
||||||
|
|
||||||
|
#define ETC_PASSWD "/etc/passwd"
|
||||||
|
|
||||||
|
#define USERADD "/usr/sbin/useradd"
|
||||||
|
#define USERMOD "/usr/sbin/usermod"
|
||||||
|
#define USERDEL "/usr/sbin/userdel"
|
||||||
|
|
||||||
|
#define BUFLEN 4096
|
||||||
|
|
||||||
|
#define UNCONFIRMED_AGEOUT_DEFAULT 600
|
||||||
|
#define UNCONFIRMED_CLEAR_LIMIT_DEFAULT 10
|
||||||
|
|
||||||
|
#define RADIUS_CONFIRMED 0
|
||||||
|
#define RADIUS_UNCONFIRMED 1
|
||||||
|
|
||||||
|
#if defined(TEST_RADIUS_NSS)
|
||||||
|
|
||||||
|
#undef RADIUS_NSS_CONF
|
||||||
|
#define RADIUS_NSS_CONF "radius_nss.conf"
|
||||||
|
|
||||||
|
#undef RADIUS_CACHE_DIR
|
||||||
|
#define RADIUS_CACHE_DIR "."
|
||||||
|
|
||||||
|
#undef RADIUS_ATTRIBUTE_CACHE_DIR
|
||||||
|
#define RADIUS_ATTRIBUTE_CACHE_DIR "user"
|
||||||
|
|
||||||
|
|
||||||
|
#undef ETC_PASSWD
|
||||||
|
#define ETC_PASSWD "passwd"
|
||||||
|
|
||||||
|
#undef USERADD
|
||||||
|
#define USERADD "/bin/echo"
|
||||||
|
#undef USERMOD
|
||||||
|
#define USERMOD "/bin/echo"
|
||||||
|
#undef USERDEL
|
||||||
|
#define USERDEL "/bin/echo"
|
||||||
|
|
||||||
|
#define syslog(priority,format,...) fprintf(stderr,format"\n",__VA_ARGS__)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define STATUS_EPERM 1
|
||||||
|
#define STATUS_ENOENT 2
|
||||||
|
#define STATUS_ESRCH 3
|
||||||
|
#define STATUS_EIO 5
|
||||||
|
#define STATUS_E2BIG 7
|
||||||
|
#define STATUS_EINVAL 22
|
||||||
|
#define STATUS_EFBIG 27
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _radius_nss_mpl {
|
||||||
|
gid_t gid;
|
||||||
|
char * groups; /* Supplementary groups */
|
||||||
|
char * gecos;
|
||||||
|
char * shell;
|
||||||
|
} RADIUS_NSS_MPL;
|
||||||
|
|
||||||
|
typedef struct _radius_nss_conf {
|
||||||
|
char * prog;
|
||||||
|
int debug;
|
||||||
|
int trace;
|
||||||
|
int many_to_one;
|
||||||
|
int allow_anonymous;
|
||||||
|
char * unconfirmed_regexp;
|
||||||
|
int unconfirmed_ageout;
|
||||||
|
int unconfirmed_clear_limit;
|
||||||
|
RADIUS_NSS_MPL rnm[RADIUS_MAX_MPL];
|
||||||
|
} RADIUS_NSS_CONF_B;
|
||||||
|
|
||||||
|
int parse_nss_config( RADIUS_NSS_CONF_B * conf, char * prog,
|
||||||
|
char * file_buf, int file_buf_sz, int * errnop, int * plockfd);
|
||||||
|
|
||||||
|
int unparse_nss_config( RADIUS_NSS_CONF_B * conf, int * errnop, int * plockfd);
|
||||||
|
|
||||||
|
int radius_lookup_cache( char * prog, const char * nam, int * pmpl);
|
||||||
|
|
||||||
|
int radius_fill_pw( RADIUS_NSS_CONF_B * conf, int mpl,
|
||||||
|
const char * nam, struct passwd * pwd,
|
||||||
|
char * buffer, size_t buflen, int * errnop);
|
||||||
|
|
||||||
|
int radius_copy_pw( RADIUS_NSS_CONF_B * conf, struct passwd * res,
|
||||||
|
const char * nam, struct passwd * pwd,
|
||||||
|
char * buffer, size_t buflen, int * errnop);
|
||||||
|
|
||||||
|
int is_sshd_lookup(RADIUS_NSS_CONF_B * conf, const char * nam);
|
||||||
|
|
||||||
|
int radius_getpwnam_r(char * prog, const char * name,
|
||||||
|
struct passwd * pwd, char * buf, int buflen, struct passwd ** result);
|
||||||
|
int radius_update_user(RADIUS_NSS_CONF_B * conf, const char * user, int mpl);
|
||||||
|
int radius_create_user(RADIUS_NSS_CONF_B * conf, const char * user, int mpl,
|
||||||
|
int unconfirmed);
|
||||||
|
int radius_clear_unconfirmed_users(RADIUS_NSS_CONF_B * conf);
|
||||||
|
|
19
src/radius/nss/libnss-radius/rbash_restriction.sh
Normal file
19
src/radius/nss/libnss-radius/rbash_restriction.sh
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Copyright 2019 Broadcom. All rights reserved.
|
||||||
|
# The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
#
|
||||||
|
#######################################################################
|
||||||
|
#
|
||||||
|
# Restrict rbash
|
||||||
|
#
|
||||||
|
|
||||||
|
if [ "$0" == "rbash" ] ; then
|
||||||
|
|
||||||
|
# Prevent from executing arbitrary commands. Only allow CWD commands
|
||||||
|
# Add shell scripts to the user's home directory to allow them to run
|
||||||
|
# commands.
|
||||||
|
|
||||||
|
PATH=
|
||||||
|
export PATH
|
||||||
|
fi
|
62
src/radius/nss/libnss-radius/test_nss_radius.c
Normal file
62
src/radius/nss/libnss-radius/test_nss_radius.c
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 Broadcom. All rights reserved.
|
||||||
|
The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test code for _nss_radius_getpwnam_r(): NSS entry point for getpwnam
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <nss.h>
|
||||||
|
|
||||||
|
int main(int ac, char * av[]) {
|
||||||
|
|
||||||
|
|
||||||
|
enum nss_status status;
|
||||||
|
struct passwd pw;
|
||||||
|
char buf[256];
|
||||||
|
int errno;
|
||||||
|
|
||||||
|
char * users[] = { "admin", "user", "netops", "operator", "unknown", 0 };
|
||||||
|
char ** u;
|
||||||
|
|
||||||
|
printf("buf: %p, len: %lx\n", buf, sizeof(buf));
|
||||||
|
|
||||||
|
for ( u = users ; *u ; u++) {
|
||||||
|
status = _nss_radius_getpwnam_r( *u, &pw, buf, sizeof(buf),
|
||||||
|
&errno);
|
||||||
|
|
||||||
|
printf("\n%s: status:%d\n", *u, status);
|
||||||
|
|
||||||
|
if (status != NSS_STATUS_SUCCESS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
printf("\tnam: %s, passwd: %s, uid: %u, gid: %u\n",
|
||||||
|
pw.pw_name, pw.pw_passwd, pw.pw_uid, pw.pw_gid);
|
||||||
|
printf("\tnam: %p, passwd: %p, uid: %u, gid: %u\n",
|
||||||
|
pw.pw_name, pw.pw_passwd, pw.pw_uid, pw.pw_gid);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("\tgecos: %s, dir: %s, shell: %s\n",
|
||||||
|
pw.pw_gecos, pw.pw_dir, pw.pw_shell);
|
||||||
|
printf("\tgecos: %p, dir: %p, shell: %p\n",
|
||||||
|
pw.pw_gecos, pw.pw_dir, pw.pw_shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
0
src/radius/nss/patches/.gitignore
vendored
Normal file
0
src/radius/nss/patches/.gitignore
vendored
Normal file
1
src/radius/pam/.gitignore
vendored
Normal file
1
src/radius/pam/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
pam_radius
|
43
src/radius/pam/Makefile
Normal file
43
src/radius/pam/Makefile
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
.ONESHELL:
|
||||||
|
SHELL = /bin/bash
|
||||||
|
.SHELLFLAGS += -e
|
||||||
|
|
||||||
|
MAIN_TARGET = libpam-radius-auth_$(PAM_RADIUS_VERSION)_amd64.deb
|
||||||
|
|
||||||
|
$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% :
|
||||||
|
# Build freeradius-server v1.1.x
|
||||||
|
pushd freeradius
|
||||||
|
-rm -rf freeradius-server
|
||||||
|
git clone https://github.com/FreeRADIUS/freeradius-server.git
|
||||||
|
popd
|
||||||
|
pushd freeradius/freeradius-server
|
||||||
|
git checkout -f 5f715dba4d2dbdb268bf60fcc656352274930941
|
||||||
|
# Apply patch
|
||||||
|
patch -p1 < ../patches/freeradius_configure.patch
|
||||||
|
patch -p1 < ../patches/freeradius_2007-04-06.patch
|
||||||
|
patch -p1 < ../patches/freeradius_libeap_deprecated_openssl_1_0.patch
|
||||||
|
./configure --disable-static --enable-libtool-lock
|
||||||
|
make
|
||||||
|
popd
|
||||||
|
|
||||||
|
# Obtain pam_radius
|
||||||
|
-rm -rf ./pam_radius
|
||||||
|
git clone https://github.com/FreeRADIUS/pam_radius.git
|
||||||
|
pushd ./pam_radius
|
||||||
|
# This is the latest commit with Radius MPL support
|
||||||
|
git checkout -f 149c25df84cf5cd0e9addd9346699a9ca8fdddd2
|
||||||
|
|
||||||
|
cp -r ../debian .
|
||||||
|
cp -r ../patches .
|
||||||
|
|
||||||
|
# Apply patch
|
||||||
|
git apply patches/0001-chap-support.patch
|
||||||
|
git apply patches/0002-peap-mschapv2-support.patch
|
||||||
|
git apply patches/0003-nas-ip-address-config.patch
|
||||||
|
|
||||||
|
dpkg-buildpackage -rfakeroot -b -us -uc -nc
|
||||||
|
popd
|
||||||
|
|
||||||
|
mv $(DERIVED_TARGETS) $* $(DEST)/
|
||||||
|
|
||||||
|
$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET)
|
5
src/radius/pam/debian/README.Debian
Normal file
5
src/radius/pam/debian/README.Debian
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
NOTE: The Debian version of libpam-radius-auth uses as default configuration
|
||||||
|
file /etc/pam_radius_auth.conf.
|
||||||
|
Upstream has a default set to /etc/raddb/server that does not fit in Debian.
|
||||||
|
Be aware that the documentation references has not been changed and they
|
||||||
|
reflect upstream setups.
|
5
src/radius/pam/debian/changelog
Normal file
5
src/radius/pam/debian/changelog
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
libpam-radius-auth (1.4.1-1) unstable; urgency=low
|
||||||
|
|
||||||
|
* Initial version.
|
||||||
|
|
||||||
|
-- Arun Barboza <29963827+a-barboza@users.noreply.github.com> Tue, 13 Aug 2019 16:46:25 -0700
|
1
src/radius/pam/debian/compat
Normal file
1
src/radius/pam/debian/compat
Normal file
@ -0,0 +1 @@
|
|||||||
|
10
|
16
src/radius/pam/debian/control
Normal file
16
src/radius/pam/debian/control
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
Source: libpam-radius-auth
|
||||||
|
Maintainer: Arun Barboza <29963827+a-barboza@users.noreply.github.com>
|
||||||
|
Section: libs
|
||||||
|
Priority: extra
|
||||||
|
Standards-Version: 3.6.2
|
||||||
|
Build-Depends: libpam0g-dev | libpam-dev, debhelper (>= 10~)
|
||||||
|
|
||||||
|
Package: libpam-radius-auth
|
||||||
|
Architecture: any
|
||||||
|
Depends: ${shlibs:Depends}
|
||||||
|
Suggests: radius-server
|
||||||
|
Description: The PAM RADIUS authentication module
|
||||||
|
This is the PAM to RADIUS authentication module. It allows any PAM-capable
|
||||||
|
machine to become a RADIUS client for authentication and accounting
|
||||||
|
requests. You will, however, need to supply your own RADIUS server to
|
||||||
|
perform the actual authentication
|
284
src/radius/pam/debian/copyright
Normal file
284
src/radius/pam/debian/copyright
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
Please see the individual src files for the copyright
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
675 Mass Ave, Cambridge, MA 02139, USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
36
src/radius/pam/debian/index.html
Normal file
36
src/radius/pam/debian/index.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<TITLE><code>pam_radius_auth</CODE>: The PAM RADIUS authentication module</TITLE>
|
||||||
|
<BODY BGCOLOR=#FFFFFF TEXT=#000000>
|
||||||
|
|
||||||
|
<H1><code>pam_radius_auth</CODE>: The PAM RADIUS authentication module</H1>
|
||||||
|
|
||||||
|
This is the PAM to RADIUS authentication module. It allows any
|
||||||
|
PAM-capable machine to become a RADIUS client for authentication and
|
||||||
|
accounting requests. You will need a RADIUS server to perform the
|
||||||
|
actual authentication.
|
||||||
|
|
||||||
|
<P><HR>
|
||||||
|
<H2>Files included with the module</H2>
|
||||||
|
|
||||||
|
<A HREF="../README.gz">README</A> <EM>Introduction and documentation</EM><BR>
|
||||||
|
<A HREF="../examples/INSTALL.gz">INSTALL</A> <EM>Installation instructions</EM><BR>
|
||||||
|
<A HREF="../USAGE.gz">USAGE</A> <EM>Module configuration and usage documentation</EM><BR>
|
||||||
|
<A HREF="../changelog.gz">Changelog</A> <EM>What's changed</EM><BR>
|
||||||
|
<A HREF="../examples/pam_radius_auth.conf">pam_radius_auth.conf</A> <EM>Sample
|
||||||
|
configuration file for telling the client the location of the RADIUS server.</EM><BR>
|
||||||
|
<A HREF="../examples/pam_example">Mini Debian HOWTO</A> <EM>C source file</EM><BR>
|
||||||
|
<A HREF=""></A> <EM></EM><BR>
|
||||||
|
|
||||||
|
|
||||||
|
<P><HR>
|
||||||
|
<H2>Updates</H2>
|
||||||
|
|
||||||
|
For the latest version and updates, see the main web or ftp site:
|
||||||
|
<P>
|
||||||
|
<A HREF="http://www.freeradius.org/pam_radius_auth/">http://www.freeradius.org/pam_radius_auth/</A><BR>
|
||||||
|
<A HREF="ftp://ftp.freeradius.org/pub/radius/pam_radius_auth.tar">ftp://ftp.freeradius.org/pub/radius/pam_radius_auth.tar</A>
|
||||||
|
<P><HR>
|
||||||
|
<EM>$Id: index.html,v 1.4 2001/03/30 19:01:56 aland Exp $</EM>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
64
src/radius/pam/debian/pam_example
Normal file
64
src/radius/pam/debian/pam_example
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
This is a simple and safe example on how to enable radius
|
||||||
|
authentication to the console login on a Debian system and
|
||||||
|
you are too lazy to read the USAGE documentation.
|
||||||
|
|
||||||
|
Edit /etc/pam.d/login
|
||||||
|
|
||||||
|
The default looks like:
|
||||||
|
|
||||||
|
[SNIP]
|
||||||
|
|
||||||
|
# Disallows other than root logins when /etc/nologin exists
|
||||||
|
# (Replaces the `NOLOGINS_FILE' option from login.defs)
|
||||||
|
auth requisite pam_nologin.so
|
||||||
|
|
||||||
|
# This module parses /etc/environment (the standard for setting
|
||||||
|
# environ vars) and also allows you to use an extended config
|
||||||
|
# file /etc/security/pam_env.conf.
|
||||||
|
# (Replaces the `ENVIRON_FILE' setting from login.defs)
|
||||||
|
auth required pam_env.so
|
||||||
|
|
||||||
|
# Standard Un*x authentication. The "nullok" line allows passwordless
|
||||||
|
# accounts.
|
||||||
|
@include common-auth
|
||||||
|
|
||||||
|
[SNIP]
|
||||||
|
|
||||||
|
|
||||||
|
Insert the following line:
|
||||||
|
|
||||||
|
auth sufficient pam_radius_auth.so
|
||||||
|
|
||||||
|
AFTER
|
||||||
|
|
||||||
|
auth required pam_env.so
|
||||||
|
|
||||||
|
and BEFORE
|
||||||
|
|
||||||
|
# Standard Un*x authentication. The "nullok" line allows passwordless
|
||||||
|
# accounts.
|
||||||
|
@include common-auth
|
||||||
|
|
||||||
|
so that it will looks like:
|
||||||
|
|
||||||
|
[SNIP]
|
||||||
|
|
||||||
|
# This module parses /etc/environment (the standard for setting
|
||||||
|
# environ vars) and also allows you to use an extended config
|
||||||
|
# file /etc/security/pam_env.conf.
|
||||||
|
# (Replaces the `ENVIRON_FILE' setting from login.defs)
|
||||||
|
auth required pam_env.so
|
||||||
|
|
||||||
|
##### RADIUS #####
|
||||||
|
auth sufficient pam_radius_auth.so
|
||||||
|
|
||||||
|
# Standard Un*x authentication. The "nullok" line allows passwordless
|
||||||
|
# accounts.
|
||||||
|
@include common-auth
|
||||||
|
|
||||||
|
[SNIP]
|
||||||
|
|
||||||
|
Try now to login in one of the consoles using the radius password.
|
||||||
|
If it fails the system will prompt again for a password. This time
|
||||||
|
provide the local one.
|
||||||
|
|
116
src/radius/pam/debian/rules
Executable file
116
src/radius/pam/debian/rules
Executable file
@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
export DH_VERBOSE=1
|
||||||
|
|
||||||
|
# Build options.
|
||||||
|
CC=gcc
|
||||||
|
CFLAGS= -g -Wall -fPIC -DCONF_FILE=\"/etc/pam_radius_auth.conf\"
|
||||||
|
#LDFLAGS=
|
||||||
|
#CFLAGS= -g -Wall -fPIC
|
||||||
|
#LDFLAGS = -shared
|
||||||
|
|
||||||
|
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||||
|
CFLAGS += -O0
|
||||||
|
else
|
||||||
|
CFLAGS += -O2
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DEB_HOST_GNU_CPU),(hppa|m68k|mips|powerpc|s390|sparc|sparc64|sheb))
|
||||||
|
CFLAGS += -DHIGHFIRST
|
||||||
|
endif
|
||||||
|
|
||||||
|
export CFLAGS
|
||||||
|
#export LDFLAGS
|
||||||
|
export CC
|
||||||
|
|
||||||
|
build: patch build-stamp
|
||||||
|
|
||||||
|
build-stamp:
|
||||||
|
dh_testdir
|
||||||
|
|
||||||
|
# Add here commands to compile the package.
|
||||||
|
dh_auto_configure -- --enable-pamdir=/lib/$(DEB_HOST_MULTIARCH)/security
|
||||||
|
|
||||||
|
# $(MAKE) -e
|
||||||
|
$(MAKE)
|
||||||
|
|
||||||
|
touch build-stamp
|
||||||
|
|
||||||
|
#patch:
|
||||||
|
# if [ ! -f patch-stamp ]; then \
|
||||||
|
# patch -p1 < debian/patches/001.fix_Makefile.diff && \
|
||||||
|
# patch -p1 < debian/patches/002.CAN2005-0108.diff && \
|
||||||
|
# touch patch-stamp; \
|
||||||
|
# fi
|
||||||
|
#
|
||||||
|
#unpatch:
|
||||||
|
# if [ -f patch-stamp ]; then \
|
||||||
|
# patch -Rp1 < debian/patches/002.CAN2005-0108.diff && \
|
||||||
|
# patch -Rp1 < debian/patches/001.fix_Makefile.diff && \
|
||||||
|
# rm -f patch-stamp; \
|
||||||
|
# fi
|
||||||
|
|
||||||
|
patch:
|
||||||
|
if [ ! -f patch-stamp ]; then \
|
||||||
|
touch patch-stamp; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
unpatch:
|
||||||
|
if [ -f patch-stamp ]; then \
|
||||||
|
rm -f patch-stamp; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
clean: unpatch real-clean
|
||||||
|
real-clean:
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
rm -f build-stamp
|
||||||
|
|
||||||
|
# Add here commands to clean up after the build process.
|
||||||
|
[ ! -f Makefile ] || $(MAKE) clean
|
||||||
|
|
||||||
|
dh_clean
|
||||||
|
|
||||||
|
install: build
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_clean -k
|
||||||
|
dh_installdirs /lib /lib/$(DEB_HOST_MULTIARCH) /lib/$(DEB_HOST_MULTIARCH)/security /etc /etc/logrotate.d /etc/pam_radius_auth.d /etc/pam_radius_auth.d/statistics /usr/share/doc/libpam-radius-auth/html
|
||||||
|
|
||||||
|
install -p pam_radius_auth.so debian/libpam-radius-auth/lib/$(DEB_HOST_MULTIARCH)/security/pam_radius_auth.so
|
||||||
|
install -p ../freeradius/freeradius-server/src/lib/.libs/libradius-1.1.8.so debian/libpam-radius-auth/lib/$(DEB_HOST_MULTIARCH)/libradius-1.1.8.so
|
||||||
|
install -p ../freeradius/freeradius-server/src/modules/rlm_eap/libeap/.libs/libeap-1.1.8.so debian/libpam-radius-auth/lib/$(DEB_HOST_MULTIARCH)/libeap-1.1.8.so
|
||||||
|
install -p pam_radius_auth.conf debian/libpam-radius-auth/etc/pam_radius_auth.conf
|
||||||
|
install -p pam_radius debian/libpam-radius-auth/etc/logrotate.d/pam_radius
|
||||||
|
install -p index.html debian/libpam-radius-auth/usr/share/doc/libpam-radius-auth/html/index.html
|
||||||
|
install -p debian/index.html debian/libpam-radius-auth/usr/share/doc/libpam-radius-auth/html/index.debian.html
|
||||||
|
|
||||||
|
# Build architecture-independent
|
||||||
|
binary-indep: build install
|
||||||
|
# nothing to do
|
||||||
|
|
||||||
|
# Build architecture-dependent files here.
|
||||||
|
binary-arch: build install
|
||||||
|
dh_testdir
|
||||||
|
dh_testroot
|
||||||
|
dh_installchangelogs Changelog
|
||||||
|
dh_installdocs README.rst TODO USAGE debian/README.Debian
|
||||||
|
dh_installexamples pam_radius_auth.conf debian/pam_example INSTALL
|
||||||
|
dh_strip
|
||||||
|
dh_compress usr/share/doc/libpam-radius-auth/README.rst\
|
||||||
|
usr/share/doc/libpam-radius-auth/README.Debian\
|
||||||
|
usr/share/doc/libpam-radius-auth/USAGE\
|
||||||
|
usr/share/doc/libpam-radius-auth/examples/INSTALL
|
||||||
|
dh_fixperms
|
||||||
|
chmod 600 debian/libpam-radius-auth/etc/pam_radius_auth.conf
|
||||||
|
chmod 644 debian/libpam-radius-auth/etc/logrotate.d/pam_radius
|
||||||
|
dh_makeshlibs
|
||||||
|
dh_installdeb
|
||||||
|
dh_shlibdeps
|
||||||
|
dh_gencontrol
|
||||||
|
dh_md5sums
|
||||||
|
dh_builddeb
|
||||||
|
|
||||||
|
binary: binary-arch binary-indep
|
||||||
|
.PHONY: build clean binary-arch binary install patch unpatch
|
2
src/radius/pam/freeradius/.gitignore
vendored
Normal file
2
src/radius/pam/freeradius/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
freeradius-1.1.4
|
||||||
|
freeradius-server
|
113
src/radius/pam/freeradius/patches/freeradius_2007-04-06.patch
Normal file
113
src/radius/pam/freeradius/patches/freeradius_2007-04-06.patch
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
diff -Naurp freeradius-1.1.4_orig/src/include/radiusd.h freeradius-1.1.4/src/include/radiusd.h
|
||||||
|
--- freeradius-1.1.4_orig/src/include/radiusd.h 2007-04-06 05:12:44.644347000 -0700
|
||||||
|
+++ freeradius-1.1.4/src/include/radiusd.h 2007-04-06 05:15:03.427150000 -0700
|
||||||
|
@@ -218,9 +218,9 @@ typedef struct main_config_t {
|
||||||
|
REALM *realms;
|
||||||
|
} MAIN_CONFIG_T;
|
||||||
|
|
||||||
|
-#define DEBUG if(debug_flag)log_debug
|
||||||
|
-#define DEBUG2 if (debug_flag > 1)log_debug
|
||||||
|
-#define DEBUG3 if (debug_flag > 2)log_debug
|
||||||
|
+#define DEBUG if(debug_flag) peap_log_debug
|
||||||
|
+#define DEBUG2 if (debug_flag > 1) peap_log_debug
|
||||||
|
+#define DEBUG3 if (debug_flag > 2) peap_log_debug
|
||||||
|
|
||||||
|
#define SECONDS_PER_DAY 86400
|
||||||
|
#define MAX_REQUEST_TIME 30
|
||||||
|
@@ -354,7 +354,7 @@ int radlog(int, const char *, ...)
|
||||||
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
-int log_debug(const char *, ...)
|
||||||
|
+int peap_log_debug(const char *, ...)
|
||||||
|
#ifdef __GNUC__
|
||||||
|
__attribute__ ((format (printf, 1, 2)))
|
||||||
|
#endif
|
||||||
|
--- freeradius-1.1.4_orig/Makefile 2006-06-22 21:31:58.000000000 -0700
|
||||||
|
+++ freeradius-1.1.4/Makefile 2018-01-16 23:26:04.820218000 -0800
|
||||||
|
@@ -40,31 +40,16 @@ clean:
|
||||||
|
#
|
||||||
|
export DESTDIR := $(R)
|
||||||
|
install:
|
||||||
|
- $(INSTALL) -d -m 755 $(R)$(sbindir)
|
||||||
|
- $(INSTALL) -d -m 755 $(R)$(bindir)
|
||||||
|
- $(INSTALL) -d -m 755 $(R)$(raddbdir)
|
||||||
|
- $(INSTALL) -d -m 755 $(R)$(mandir)
|
||||||
|
- $(INSTALL) -d -m 755 $(R)$(RUNDIR)
|
||||||
|
- $(INSTALL) -d -m 700 $(R)$(logdir)
|
||||||
|
- $(INSTALL) -d -m 700 $(R)$(radacctdir)
|
||||||
|
- $(INSTALL) -d -m 755 $(R)$(datadir)
|
||||||
|
- $(INSTALL) -d -m 755 $(R)$(dictdir)
|
||||||
|
- for i in 1 5 8; do \
|
||||||
|
- $(INSTALL) -d -m 755 $(R)$(mandir)/man$$i; \
|
||||||
|
- for p in man/man$$i/*.$$i; do \
|
||||||
|
- $(INSTALL) -m 644 $$p $(R)$(mandir)/man$$i; \
|
||||||
|
- done \
|
||||||
|
+ $(INSTALL) -d -m 755 $(PKG_CONFIG_SYSROOT_DIR)$(includedir)/freeradius
|
||||||
|
+ for p in src/include/*.h \
|
||||||
|
+ src/modules/rlm_eap/*.h \
|
||||||
|
+ src/modules/rlm_eap/libeap/*.h ; do \
|
||||||
|
+ $(INSTALL) -m 644 $$p \
|
||||||
|
+ $(PKG_CONFIG_SYSROOT_DIR)$(includedir)/freeradius; \
|
||||||
|
done
|
||||||
|
- @$(MAKE) $(MFLAGS) WHAT_TO_MAKE=$@ common
|
||||||
|
- @echo "Installing dictionary files in $(R)$(dictdir)"; \
|
||||||
|
- cd share; \
|
||||||
|
- for i in dictionary*; do \
|
||||||
|
- $(INSTALL) -m 644 $$i $(R)$(dictdir); \
|
||||||
|
- done
|
||||||
|
- $(LIBTOOL) --finish $(R)$(libdir)
|
||||||
|
|
||||||
|
common:
|
||||||
|
- @for dir in $(SUBDIRS); do \
|
||||||
|
+ @for dir in src; do \
|
||||||
|
echo "Making $(WHAT_TO_MAKE) in $$dir..."; \
|
||||||
|
$(MAKE) $(MFLAGS) -C $$dir $(WHAT_TO_MAKE) || exit $$?; \
|
||||||
|
done
|
||||||
|
diff -Naurp freeradius-1.1.4_orig/src/Makefile freeradius-1.1.4/src/Makefile
|
||||||
|
--- freeradius-1.1.4_orig/src/Makefile 2006-05-25 09:24:40.000000000 -0700
|
||||||
|
+++ freeradius-1.1.4/src/Makefile 2018-01-10 13:32:07.572104095 -0800
|
||||||
|
@@ -20,7 +20,7 @@ install:
|
||||||
|
@$(MAKE) $(MFLAGS) WHAT_TO_MAKE=$@ common
|
||||||
|
|
||||||
|
common:
|
||||||
|
- @for dir in $(SUBDIRS); do \
|
||||||
|
+ @for dir in include lib modules; do \
|
||||||
|
echo "Making $(WHAT_TO_MAKE) in $$dir..."; \
|
||||||
|
$(MAKE) $(MFLAGS) -C $$dir $(WHAT_TO_MAKE) || exit $$?; \
|
||||||
|
done
|
||||||
|
diff -Naurp freeradius-1.1.4_orig/src/modules/Makefile freeradius-1.1.4/src/modules/Makefile
|
||||||
|
--- freeradius-1.1.4_orig/src/modules/Makefile 2006-07-06 12:16:41.000000000 -0700
|
||||||
|
+++ freeradius-1.1.4/src/modules/Makefile 2018-01-10 13:35:28.596154618 -0800
|
||||||
|
@@ -43,7 +43,7 @@ reconfig:
|
||||||
|
|
||||||
|
common:
|
||||||
|
@[ -d lib/ ] || mkdir lib
|
||||||
|
- @for mod in $(MODULES); do \
|
||||||
|
+ @for mod in rlm_eap; do \
|
||||||
|
if [ -d $$mod ] && [ -f $$mod/Makefile ]; then \
|
||||||
|
echo "Making $(WHAT_TO_MAKE) in $$mod..."; \
|
||||||
|
$(MAKE) $(MFLAGS) -C $$mod $(WHAT_TO_MAKE) || exit $$?; \
|
||||||
|
diff -Naurp freeradius-1.1.4_orig/src/modules/rlm_eap/Makefile.in freeradius-1.1.4/src/modules/rlm_eap/Makefile.in
|
||||||
|
--- freeradius-1.1.4_orig/src/modules/rlm_eap/Makefile.in 2006-05-25 09:24:41.000000000 -0700
|
||||||
|
+++ freeradius-1.1.4/src/modules/rlm_eap/Makefile.in 2018-01-11 09:46:16.637574778 -0800
|
||||||
|
@@ -2,8 +2,8 @@
|
||||||
|
# $Id: Makefile.in,v 1.12.2.2.2.4 2006/05/25 16:24:41 nbk Exp $
|
||||||
|
#
|
||||||
|
|
||||||
|
-TARGET = @targetname@
|
||||||
|
-SRCS = rlm_eap.c eap.c mem.c state.c
|
||||||
|
+# TARGET = @targetname@
|
||||||
|
+# SRCS = rlm_eap.c eap.c mem.c state.c
|
||||||
|
HEADERS = eap.h rlm_eap.h
|
||||||
|
RLM_CFLAGS = $(INCLTDL) -Ilibeap
|
||||||
|
CLIENTLIBS = libeap/libeap.la
|
||||||
|
@@ -40,7 +40,7 @@ install-subdirs:
|
||||||
|
$(LIBTOOL) --mode=install $(INSTALL) -m 755 $(INSTALLSTRIP) radeapclient$(EXEEXT) $(R)$(bindir)
|
||||||
|
|
||||||
|
common:
|
||||||
|
- @for dir in $(RLM_SUBDIRS); do \
|
||||||
|
+ @for dir in libeap; do \
|
||||||
|
echo "Making $(WHAT_TO_MAKE) in $$dir..."; \
|
||||||
|
$(MAKE) $(MFLAGS) -C $$dir $(WHAT_TO_MAKE) || exit $$?; \
|
||||||
|
done
|
1443
src/radius/pam/freeradius/patches/freeradius_configure.patch
Normal file
1443
src/radius/pam/freeradius/patches/freeradius_configure.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,130 @@
|
|||||||
|
diff -Naurp freeradius-1.1.4_orig/src/modules/rlm_eap/libeap/mppe_keys.c freeradius-1.1.4/src/modules/rlm_eap/libeap/mppe_keys.c
|
||||||
|
--- freeradius-1.1.4_orig/src/modules/rlm_eap/libeap/mppe_keys.c 2019-11-05 17:47:48.118829000 -0800
|
||||||
|
+++ freeradius-1.1.4/src/modules/rlm_eap/libeap/mppe_keys.c 2019-11-05 19:23:35.176930000 -0800
|
||||||
|
@@ -52,47 +52,55 @@ static void P_hash(const EVP_MD *evp_md,
|
||||||
|
const unsigned char *seed, unsigned int seed_len,
|
||||||
|
unsigned char *out, unsigned int out_len)
|
||||||
|
{
|
||||||
|
- HMAC_CTX ctx_a, ctx_out;
|
||||||
|
+ HMAC_CTX * ctx_a, * ctx_out;
|
||||||
|
unsigned char a[HMAC_MAX_MD_CBLOCK];
|
||||||
|
unsigned int size;
|
||||||
|
|
||||||
|
- HMAC_CTX_init(&ctx_a);
|
||||||
|
- HMAC_CTX_init(&ctx_out);
|
||||||
|
- HMAC_Init_ex(&ctx_a, secret, secret_len, evp_md, NULL);
|
||||||
|
- HMAC_Init_ex(&ctx_out, secret, secret_len, evp_md, NULL);
|
||||||
|
+ if (NULL == (ctx_a = HMAC_CTX_new())) {
|
||||||
|
+ DEBUG("P_hash: HMAC_CTX_new() failed\n");
|
||||||
|
+ goto P_hash_exit;
|
||||||
|
+ }
|
||||||
|
+ if (NULL == (ctx_out = HMAC_CTX_new())) {
|
||||||
|
+ DEBUG("P_hash: HMAC_CTX_new() failed\n");
|
||||||
|
+ goto P_hash_exit;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ HMAC_Init_ex(ctx_a, secret, secret_len, evp_md, NULL);
|
||||||
|
+ HMAC_Init_ex(ctx_out, secret, secret_len, evp_md, NULL);
|
||||||
|
|
||||||
|
- size = HMAC_size(&ctx_out);
|
||||||
|
+ size = HMAC_size(ctx_out);
|
||||||
|
|
||||||
|
/* Calculate A(1) */
|
||||||
|
- HMAC_Update(&ctx_a, seed, seed_len);
|
||||||
|
- HMAC_Final(&ctx_a, a, NULL);
|
||||||
|
+ HMAC_Update(ctx_a, seed, seed_len);
|
||||||
|
+ HMAC_Final(ctx_a, a, NULL);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/* Calculate next part of output */
|
||||||
|
- HMAC_Update(&ctx_out, a, size);
|
||||||
|
- HMAC_Update(&ctx_out, seed, seed_len);
|
||||||
|
+ HMAC_Update(ctx_out, a, size);
|
||||||
|
+ HMAC_Update(ctx_out, seed, seed_len);
|
||||||
|
|
||||||
|
/* Check if last part */
|
||||||
|
if (out_len < size) {
|
||||||
|
- HMAC_Final(&ctx_out, a, NULL);
|
||||||
|
+ HMAC_Final(ctx_out, a, NULL);
|
||||||
|
memcpy(out, a, out_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Place digest in output buffer */
|
||||||
|
- HMAC_Final(&ctx_out, out, NULL);
|
||||||
|
- HMAC_Init_ex(&ctx_out, NULL, 0, NULL, NULL);
|
||||||
|
+ HMAC_Final(ctx_out, out, NULL);
|
||||||
|
+ HMAC_Init_ex(ctx_out, NULL, 0, NULL, NULL);
|
||||||
|
out += size;
|
||||||
|
out_len -= size;
|
||||||
|
|
||||||
|
/* Calculate next A(i) */
|
||||||
|
- HMAC_Init_ex(&ctx_a, NULL, 0, NULL, NULL);
|
||||||
|
- HMAC_Update(&ctx_a, a, size);
|
||||||
|
- HMAC_Final(&ctx_a, a, NULL);
|
||||||
|
+ HMAC_Init_ex(ctx_a, NULL, 0, NULL, NULL);
|
||||||
|
+ HMAC_Update(ctx_a, a, size);
|
||||||
|
+ HMAC_Final(ctx_a, a, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
- HMAC_CTX_cleanup(&ctx_a);
|
||||||
|
- HMAC_CTX_cleanup(&ctx_out);
|
||||||
|
+P_hash_exit:
|
||||||
|
+ if (ctx_a) HMAC_CTX_free(ctx_a);
|
||||||
|
+ if (ctx_out) HMAC_CTX_free(ctx_out);
|
||||||
|
memset(a, 0, sizeof(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -127,21 +135,25 @@ void eaptls_gen_mppe_keys(VALUE_PAIR **r
|
||||||
|
unsigned char seed[64 + 2*SSL3_RANDOM_SIZE];
|
||||||
|
unsigned char *p = seed;
|
||||||
|
size_t prf_size;
|
||||||
|
+ unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
|
||||||
|
+ size_t master_key_len;
|
||||||
|
|
||||||
|
prf_size = strlen(prf_label);
|
||||||
|
|
||||||
|
memcpy(p, prf_label, prf_size);
|
||||||
|
p += prf_size;
|
||||||
|
|
||||||
|
- memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
|
||||||
|
+ SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
|
||||||
|
p += SSL3_RANDOM_SIZE;
|
||||||
|
prf_size += SSL3_RANDOM_SIZE;
|
||||||
|
|
||||||
|
- memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
|
||||||
|
+ SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
|
||||||
|
prf_size += SSL3_RANDOM_SIZE;
|
||||||
|
|
||||||
|
- PRF(s->session->master_key, s->session->master_key_length,
|
||||||
|
- seed, prf_size, out, buf, sizeof(out));
|
||||||
|
+ master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s),
|
||||||
|
+ master_key, sizeof(master_key));
|
||||||
|
+
|
||||||
|
+ PRF(master_key, master_key_len, seed, prf_size, out, buf, sizeof(out));
|
||||||
|
|
||||||
|
p = out;
|
||||||
|
add_reply(reply_vps, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN);
|
||||||
|
@@ -163,14 +175,19 @@ void eapttls_gen_challenge(SSL *s, char
|
||||||
|
unsigned char out[32], buf[32];
|
||||||
|
unsigned char seed[sizeof(EAPTLS_PRF_CHALLENGE)-1 + 2*SSL3_RANDOM_SIZE];
|
||||||
|
unsigned char *p = seed;
|
||||||
|
+ unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
|
||||||
|
+ size_t master_key_len;
|
||||||
|
|
||||||
|
memcpy(p, EAPTLS_PRF_CHALLENGE, sizeof(EAPTLS_PRF_CHALLENGE)-1);
|
||||||
|
p += sizeof(EAPTLS_PRF_CHALLENGE)-1;
|
||||||
|
- memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
|
||||||
|
+ SSL_get_client_random(s, p, SSL3_RANDOM_SIZE);
|
||||||
|
p += SSL3_RANDOM_SIZE;
|
||||||
|
- memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE);
|
||||||
|
+ SSL_get_server_random(s, p, SSL3_RANDOM_SIZE);
|
||||||
|
+
|
||||||
|
+ master_key_len = SSL_SESSION_get_master_key(SSL_get_session(s),
|
||||||
|
+ master_key, sizeof(master_key));
|
||||||
|
|
||||||
|
- PRF(s->session->master_key, s->session->master_key_length,
|
||||||
|
+ PRF(master_key, master_key_len,
|
||||||
|
seed, sizeof(seed), out, buf, sizeof(out));
|
||||||
|
|
||||||
|
memcpy(buffer, out, size);
|
133
src/radius/pam/patches/0001-chap-support.patch
Normal file
133
src/radius/pam/patches/0001-chap-support.patch
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
Index: pam_radius/src/pam_radius_auth.c
|
||||||
|
===================================================================
|
||||||
|
--- pam_radius.orig/src/pam_radius_auth.c
|
||||||
|
+++ pam_radius/src/pam_radius_auth.c
|
||||||
|
@@ -130,6 +130,15 @@ static int _pam_parse(int argc, CONST ch
|
||||||
|
} else if (!strcmp(*argv, "privilege_level")) {
|
||||||
|
conf->privilege_level = TRUE;
|
||||||
|
|
||||||
|
+ } else if (!strncmp(*argv, "protocol=", 9)) {
|
||||||
|
+ if (!strncmp((char *)*argv+9, "pap", 4)) {
|
||||||
|
+ conf->auth_type = AUTH_TYPE_PAP;
|
||||||
|
+ } else if (!strncmp((char *)*argv+9, "chap", 5)) {
|
||||||
|
+ conf->auth_type = AUTH_TYPE_CHAP;
|
||||||
|
+ } else {
|
||||||
|
+ _pam_log(LOG_WARNING, "ignoring '%s'", *argv);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
} else {
|
||||||
|
_pam_log(LOG_WARNING, "unrecognized option '%s'", *argv);
|
||||||
|
}
|
||||||
|
@@ -510,6 +519,61 @@ static void add_password(AUTH_HDR *reque
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * int add_chap_password()
|
||||||
|
+ *
|
||||||
|
+ * Description:
|
||||||
|
+ * Add a RADIUS CHAP-Password attribute to the packet.
|
||||||
|
+ *
|
||||||
|
+ * This uses the input password as the secret to construct the
|
||||||
|
+ * CHAP response. The Request Authenticator field is used as the
|
||||||
|
+ * CHAP challenge. Compute the response and send as CHAP-Password
|
||||||
|
+ * in the Access-Request.
|
||||||
|
+ *
|
||||||
|
+ * Input(s):
|
||||||
|
+ * request - pointer to RADIUS request header
|
||||||
|
+ * chap_id - CHAP ID
|
||||||
|
+ * password - password string to do CHAP
|
||||||
|
+ *
|
||||||
|
+ * Output(s):
|
||||||
|
+ * request - pointer to RADIUS request header
|
||||||
|
+ *
|
||||||
|
+ */
|
||||||
|
+static void add_chap_password(AUTH_HDR *request, unsigned char chap_id, CONST char *password)
|
||||||
|
+{
|
||||||
|
+ unsigned char resp[CHAP_VALUE_LENGTH+1];
|
||||||
|
+ unsigned char string[MAXPASS+AUTH_VECTOR_LEN+1], *ptr = string;
|
||||||
|
+ int length;
|
||||||
|
+ MD5_CTX md5_context;
|
||||||
|
+ attribute_t *attr;
|
||||||
|
+
|
||||||
|
+ length = strlen(password);
|
||||||
|
+ if (length > MAXPASS) { /* shorten the password for now */
|
||||||
|
+ _pam_log(LOG_WARNING, "invalid password length: %d. Shortening", length);
|
||||||
|
+ length = MAXPASS;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ *ptr++ = chap_id;
|
||||||
|
+ memcpy(ptr, password, length);
|
||||||
|
+ ptr += length;
|
||||||
|
+ memcpy(ptr, request->vector, AUTH_VECTOR_LEN);
|
||||||
|
+ ptr += AUTH_VECTOR_LEN;
|
||||||
|
+
|
||||||
|
+ resp[0] = chap_id;
|
||||||
|
+ MD5Init(&md5_context);
|
||||||
|
+ MD5Update(&md5_context, string, ptr - string);
|
||||||
|
+ MD5Final(resp+1, &md5_context);
|
||||||
|
+
|
||||||
|
+ attr = find_attribute(request, PW_CHAP_PASSWORD);
|
||||||
|
+ if (!attr) {
|
||||||
|
+ add_attribute(request, PW_CHAP_PASSWORD, resp, AUTH_VECTOR_LEN+1);
|
||||||
|
+ } else {
|
||||||
|
+ memcpy(attr->data, resp, AUTH_VECTOR_LEN+1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ memset( string, 0, ptr - string); /* Scrub (zeroize) it */
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void cleanup(radius_server_t *server)
|
||||||
|
{
|
||||||
|
radius_server_t *next;
|
||||||
|
@@ -804,7 +868,12 @@ static void build_radius_packet(AUTH_HDR
|
||||||
|
* Add a password, if given.
|
||||||
|
*/
|
||||||
|
if (password) {
|
||||||
|
- add_password(request, PW_PASSWORD, password, conf->server->secret);
|
||||||
|
+ if ((request->code == PW_AUTHENTICATION_REQUEST)
|
||||||
|
+ && (conf->auth_type == AUTH_TYPE_CHAP)) {
|
||||||
|
+ add_chap_password(request, request->vector[0], password);
|
||||||
|
+ } else {
|
||||||
|
+ add_password(request, PW_PASSWORD, password, conf->server->secret);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a NULL password to non-accounting requests.
|
||||||
|
@@ -1075,7 +1144,12 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
add_password(request, PW_PASSWORD, password, old_password);
|
||||||
|
add_password(request, PW_OLD_PASSWORD, old_password, old_password);
|
||||||
|
} else { /* authentication request */
|
||||||
|
- add_password(request, PW_PASSWORD, password, server->secret);
|
||||||
|
+ if ((request->code == PW_AUTHENTICATION_REQUEST)
|
||||||
|
+ && (conf->auth_type == AUTH_TYPE_CHAP)) {
|
||||||
|
+ add_chap_password(request, request->vector[0], password);
|
||||||
|
+ } else {
|
||||||
|
+ add_password(request, PW_PASSWORD, password, server->secret);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Index: pam_radius/src/pam_radius_auth.h
|
||||||
|
===================================================================
|
||||||
|
--- pam_radius.orig/src/pam_radius_auth.h
|
||||||
|
+++ pam_radius/src/pam_radius_auth.h
|
||||||
|
@@ -123,6 +123,10 @@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
+/* Authentication Protocol types. */
|
||||||
|
+#define AUTH_TYPE_PAP 0
|
||||||
|
+#define AUTH_TYPE_CHAP 1
|
||||||
|
+
|
||||||
|
/*************************************************************************
|
||||||
|
* Additional RADIUS definitions
|
||||||
|
*************************************************************************/
|
||||||
|
@@ -162,6 +166,7 @@ typedef struct radius_conf_t {
|
||||||
|
char prompt[MAXPROMPT];
|
||||||
|
int prompt_attribute;
|
||||||
|
int privilege_level;
|
||||||
|
+ int auth_type;
|
||||||
|
} radius_conf_t;
|
||||||
|
|
||||||
|
#endif /* PAM_RADIUS_H */
|
4631
src/radius/pam/patches/0002-peap-mschapv2-support.patch
Normal file
4631
src/radius/pam/patches/0002-peap-mschapv2-support.patch
Normal file
File diff suppressed because it is too large
Load Diff
943
src/radius/pam/patches/0003-nas-ip-address-config.patch
Normal file
943
src/radius/pam/patches/0003-nas-ip-address-config.patch
Normal file
@ -0,0 +1,943 @@
|
|||||||
|
Index: pam_radius/src/pam_radius_auth.c
|
||||||
|
===================================================================
|
||||||
|
--- pam_radius.orig/src/pam_radius_auth.c
|
||||||
|
+++ pam_radius/src/pam_radius_auth.c
|
||||||
|
@@ -37,6 +37,7 @@
|
||||||
|
#define PAM_SM_SESSION
|
||||||
|
|
||||||
|
#include "pam_radius_auth.h"
|
||||||
|
+#include "pam_radius_stats.h"
|
||||||
|
|
||||||
|
#define DPRINT if (debug) _pam_log
|
||||||
|
|
||||||
|
@@ -148,7 +149,54 @@ static int _pam_parse(int argc, CONST ch
|
||||||
|
} else {
|
||||||
|
_pam_log(LOG_WARNING, "ignoring '%s'", *argv);
|
||||||
|
}
|
||||||
|
+ } else if (!strncmp(*argv, "nas_ip_address=", 15)) {
|
||||||
|
+ /* Convert it sockaddr.
|
||||||
|
+ */
|
||||||
|
+ struct addrinfo hints;
|
||||||
|
+ struct addrinfo *ai_start;
|
||||||
|
+ struct addrinfo *ai;
|
||||||
|
+ int r;
|
||||||
|
+
|
||||||
|
+ memset(&hints, 0, sizeof(hints));
|
||||||
|
+ hints.ai_family = AF_UNSPEC;
|
||||||
|
+ hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
+ hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICHOST;
|
||||||
|
+
|
||||||
|
+ r = getaddrinfo(*argv+15, NULL, &hints, &ai_start);
|
||||||
|
+ if (r != 0) {
|
||||||
|
+ _pam_log(LOG_WARNING, "getaddrinfo() fails. ignoring '%s'", *argv);
|
||||||
|
+ } else {
|
||||||
|
+
|
||||||
|
+ ai = ai_start;
|
||||||
|
+ while (ai != NULL) {
|
||||||
|
+ if (ai->ai_family == AF_INET) {
|
||||||
|
+ memcpy(&(conf->client_ip_storage), ((struct sockaddr_in *)ai->ai_addr),
|
||||||
|
+ sizeof(struct sockaddr_in));
|
||||||
|
+ conf->client_ip = (struct sockaddr *) &(conf->client_ip_storage);
|
||||||
|
+ break;
|
||||||
|
+ } else if (ai->ai_family == AF_INET6) {
|
||||||
|
+ memcpy(&(conf->client_ip_storage), ((struct sockaddr_in6 *)ai->ai_addr),
|
||||||
|
+ sizeof(struct sockaddr_in6));
|
||||||
|
+ conf->client_ip = (struct sockaddr *) &(conf->client_ip_storage);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!(conf->client_ip))
|
||||||
|
+ _pam_log(LOG_WARNING, "Invalid address. ignoring '%s'", *argv);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
|
||||||
|
+ } else if (!strncmp(*argv, "statistics=", 11)) {
|
||||||
|
+ /* Verify filename doesn't contain '/'.
|
||||||
|
+ */
|
||||||
|
+ if (!strchr(*argv+11, '/'))
|
||||||
|
+ conf->statistics = *argv+11;
|
||||||
|
+ else
|
||||||
|
+ _pam_log(LOG_WARNING, "'/' present, ignoring '%s'", *argv);
|
||||||
|
+
|
||||||
|
+ } else if (!strncmp(*argv, "trace", 5)) {
|
||||||
|
+ conf->trace = "pam_radius_trace.log";
|
||||||
|
} else {
|
||||||
|
_pam_log(LOG_WARNING, "unrecognized option '%s'", *argv);
|
||||||
|
}
|
||||||
|
@@ -424,13 +472,30 @@ static void add_int_attribute(AUTH_HDR *
|
||||||
|
add_attribute(request, type, (unsigned char *) &value, sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void add_nas_ip_address(AUTH_HDR *request, char *hostname) {
|
||||||
|
+static void add_nas_ip_address(AUTH_HDR *request, char *hostname, radius_conf_t * conf) {
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo *ai_start;
|
||||||
|
struct addrinfo *ai;
|
||||||
|
int v4seen = 0, v6seen = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
+ /* If there is a client_ip configured/discovered, use it instead.
|
||||||
|
+ */
|
||||||
|
+ if (conf->client_ip) {
|
||||||
|
+ if ((conf->client_ip)->sa_family == AF_INET) {
|
||||||
|
+ r = ((struct sockaddr_in *)(conf->client_ip))->sin_addr.s_addr;
|
||||||
|
+ add_int_attribute(request, PW_NAS_IP_ADDRESS, ntohl(r));
|
||||||
|
+ v4seen = 1;
|
||||||
|
+ } else if ((conf->client_ip)->sa_family == AF_INET6) {
|
||||||
|
+ add_attribute(request, PW_NAS_IPV6_ADDRESS,
|
||||||
|
+ (unsigned char *) &(((struct sockaddr_in6 *)conf->client_ip)->sin6_addr), 16);
|
||||||
|
+ v6seen = 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (v4seen || v6seen)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
|
@@ -446,16 +511,25 @@ static void add_nas_ip_address(AUTH_HDR
|
||||||
|
v4seen = 1;
|
||||||
|
r = ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr;
|
||||||
|
add_int_attribute(request, PW_NAS_IP_ADDRESS, ntohl(r));
|
||||||
|
+ memcpy(&(conf->client_ip_storage), ((struct sockaddr_in *)ai->ai_addr),
|
||||||
|
+ sizeof(struct sockaddr_in));
|
||||||
|
+ conf->client_ip = (struct sockaddr *) &(conf->client_ip_storage);
|
||||||
|
}
|
||||||
|
if (!v6seen && ai->ai_family == AF_INET6) {
|
||||||
|
v6seen = 1;
|
||||||
|
add_attribute(request, PW_NAS_IPV6_ADDRESS,
|
||||||
|
(unsigned char *) &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, 16);
|
||||||
|
+ memcpy(&(conf->client_ip_storage), ((struct sockaddr_in6 *)ai->ai_addr),
|
||||||
|
+ sizeof(struct sockaddr_in6));
|
||||||
|
+ conf->client_ip = (struct sockaddr *) &(conf->client_ip_storage);
|
||||||
|
}
|
||||||
|
ai = ai->ai_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(ai_start);
|
||||||
|
+
|
||||||
|
+ if (!conf->client_ip)
|
||||||
|
+ conf->client_ip = (struct sockaddr *)(&(conf->client_ip_storage));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -893,7 +967,7 @@ static void build_radius_packet(AUTH_HDR
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perhaps add NAS IP Address (and v6 version) */
|
||||||
|
- add_nas_ip_address(request, hostname);
|
||||||
|
+ add_nas_ip_address(request, hostname, conf);
|
||||||
|
|
||||||
|
/* There's always a NAS identifier */
|
||||||
|
if (conf->client_id && *conf->client_id) {
|
||||||
|
@@ -932,6 +1006,8 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
int retval;
|
||||||
|
int sockfd;
|
||||||
|
socklen_t salen;
|
||||||
|
+ struct sockaddr_storage saremote;
|
||||||
|
+ socklen_t saremotelen;
|
||||||
|
|
||||||
|
/* ************************************************************ */
|
||||||
|
/* Now that we're done building the request, we can send it */
|
||||||
|
@@ -1026,12 +1102,16 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
total_length = ntohs(request->length);
|
||||||
|
server_tries = tries;
|
||||||
|
send:
|
||||||
|
+ _pam_radius_incr( conf, request->code);
|
||||||
|
if (server->ip->sa_family == AF_INET) {
|
||||||
|
salen = sizeof(struct sockaddr_in);
|
||||||
|
} else {
|
||||||
|
salen = sizeof(struct sockaddr_in6);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ _pam_radius_trace( conf, TRUE, server->ip,
|
||||||
|
+ (unsigned char *) request, total_length);
|
||||||
|
+
|
||||||
|
/* send the packet */
|
||||||
|
if (sendto(sockfd, (char *) request, total_length, 0,
|
||||||
|
server->ip, salen) < 0) {
|
||||||
|
@@ -1072,9 +1152,11 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
if (rcode == 0) {
|
||||||
|
_pam_log(LOG_ERR, "RADIUS server %s failed to respond", server->hostname);
|
||||||
|
if (--server_tries) {
|
||||||
|
+ _pam_radius_incr( conf, STATS_RETRY(request->code));
|
||||||
|
goto send;
|
||||||
|
}
|
||||||
|
ok = FALSE;
|
||||||
|
+ _pam_radius_incr( conf, STATS_TIMEOUT);
|
||||||
|
break; /* exit from the loop */
|
||||||
|
} else if (rcode < 0) {
|
||||||
|
|
||||||
|
@@ -1111,8 +1193,10 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* try to receive some data */
|
||||||
|
+ memset((char *) &saremote, 0, sizeof(saremote));
|
||||||
|
+ saremotelen = sizeof(saremote);
|
||||||
|
if ((total_length = recvfrom(sockfd, (void *) response, BUFFER_SIZE,
|
||||||
|
- 0, NULL, NULL)) < 0) {
|
||||||
|
+ 0, (struct sockaddr *) &saremote, &saremotelen)) < 0) {
|
||||||
|
char error_string[BUFFER_SIZE];
|
||||||
|
get_error_string(errno, error_string, sizeof(error_string));
|
||||||
|
_pam_log(LOG_ERR, "error reading RADIUS packet from server %s: %s",
|
||||||
|
@@ -1122,6 +1206,10 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
|
||||||
|
/* there's data, see if it's valid */
|
||||||
|
} else {
|
||||||
|
+
|
||||||
|
+ _pam_radius_trace( conf, FALSE, (struct sockaddr *) &saremote,
|
||||||
|
+ (unsigned char *) response, total_length);
|
||||||
|
+
|
||||||
|
char *p = server->secret;
|
||||||
|
|
||||||
|
if ((ntohs(response->length) != total_length) ||
|
||||||
|
@@ -1129,6 +1217,7 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
_pam_log(LOG_ERR, "RADIUS packet from server %s is corrupted",
|
||||||
|
server->hostname);
|
||||||
|
ok = FALSE;
|
||||||
|
+ _pam_radius_incr( conf, STATS_INVALID_PACKET);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1155,6 +1244,7 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
_pam_log(LOG_ERR, "packet from RADIUS server %s failed verification: "
|
||||||
|
"The shared secret is probably incorrect.", server->hostname);
|
||||||
|
ok = FALSE;
|
||||||
|
+ _pam_radius_incr( conf, STATS_BAD_AUTHENTICATOR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1166,6 +1256,7 @@ static int talk_radius(radius_conf_t *co
|
||||||
|
"request packet ID %d: verification of packet fails",
|
||||||
|
response->id, request->id);
|
||||||
|
ok = FALSE;
|
||||||
|
+ _pam_radius_incr( conf, STATS_INVALID_PACKET);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1418,6 +1509,8 @@ PAM_EXTERN int pam_sm_authenticate(pam_h
|
||||||
|
retval = talk_radius(&config, request, response, password, NULL, config.retries + 1);
|
||||||
|
PAM_FAIL_CHECK;
|
||||||
|
|
||||||
|
+ _pam_radius_incr( &config, response->code);
|
||||||
|
+
|
||||||
|
DPRINT(LOG_DEBUG, "Got RADIUS response code %d", response->code);
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -1485,6 +1578,8 @@ PAM_EXTERN int pam_sm_authenticate(pam_h
|
||||||
|
retval = talk_radius(&config, request, response, resp2challenge, NULL, 1);
|
||||||
|
PAM_FAIL_CHECK;
|
||||||
|
|
||||||
|
+ _pam_radius_incr( &config, response->code);
|
||||||
|
+
|
||||||
|
DPRINT(LOG_DEBUG, "Got response to challenge code %d", response->code);
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -1677,6 +1772,8 @@ static int pam_private_session(pam_handl
|
||||||
|
retval = talk_radius(&config, request, response, NULL, NULL, 1);
|
||||||
|
PAM_FAIL_CHECK;
|
||||||
|
|
||||||
|
+ _pam_radius_incr( &config, response->code);
|
||||||
|
+
|
||||||
|
/* oops! They don't have the right password. Complain and die. */
|
||||||
|
if (response->code != PW_ACCOUNTING_RESPONSE) {
|
||||||
|
retval = PAM_PERM_DENIED;
|
||||||
|
@@ -1792,6 +1889,8 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand
|
||||||
|
retval = talk_radius(&config, request, response, password, NULL, 1);
|
||||||
|
PAM_FAIL_CHECK;
|
||||||
|
|
||||||
|
+ _pam_radius_incr( &config, response->code);
|
||||||
|
+
|
||||||
|
/* oops! They don't have the right password. Complain and die. */
|
||||||
|
if (response->code != PW_AUTHENTICATION_ACK) {
|
||||||
|
_pam_forget(password);
|
||||||
|
@@ -1895,6 +1994,8 @@ PAM_EXTERN int pam_sm_chauthtok(pam_hand
|
||||||
|
retval = talk_radius(&config, request, response, new_password, password, 1);
|
||||||
|
PAM_FAIL_CHECK;
|
||||||
|
|
||||||
|
+ _pam_radius_incr( &config, response->code);
|
||||||
|
+
|
||||||
|
/* Whew! Done password changing, check for password acknowledge */
|
||||||
|
if (response->code != PW_PASSWORD_ACK) {
|
||||||
|
retval = PAM_AUTHTOK_ERR;
|
||||||
|
Index: pam_radius/src/pam_radius_auth.h
|
||||||
|
===================================================================
|
||||||
|
--- pam_radius.orig/src/pam_radius_auth.h
|
||||||
|
+++ pam_radius/src/pam_radius_auth.h
|
||||||
|
@@ -160,6 +160,8 @@ typedef struct radius_conf_t {
|
||||||
|
int retries;
|
||||||
|
int localifdown;
|
||||||
|
char *client_id;
|
||||||
|
+ struct sockaddr_storage client_ip_storage;
|
||||||
|
+ struct sockaddr *client_ip;
|
||||||
|
int accounting_bug;
|
||||||
|
int force_prompt;
|
||||||
|
int max_challenge;
|
||||||
|
@@ -171,6 +173,9 @@ typedef struct radius_conf_t {
|
||||||
|
int prompt_attribute;
|
||||||
|
int privilege_level;
|
||||||
|
int auth_type;
|
||||||
|
+#define MAXFILENAME 128
|
||||||
|
+ CONST char *trace; /* Packet Trace File */
|
||||||
|
+ CONST char *statistics; /* Statistics File */
|
||||||
|
} radius_conf_t;
|
||||||
|
|
||||||
|
#endif /* PAM_RADIUS_H */
|
||||||
|
Index: pam_radius/src/radpeapclient.c
|
||||||
|
===================================================================
|
||||||
|
--- pam_radius.orig/src/radpeapclient.c
|
||||||
|
+++ pam_radius/src/radpeapclient.c
|
||||||
|
@@ -31,6 +31,7 @@
|
||||||
|
#include "radpeapclient.h"
|
||||||
|
// #include "mschapv2.h"
|
||||||
|
// #include "pam_radius_auth.h"
|
||||||
|
+#include "pam_radius_stats.h"
|
||||||
|
|
||||||
|
static unsigned char cached_auth_challenge[16] = { 0 };
|
||||||
|
static unsigned char cached_peer_challenge[16] = { 0 };
|
||||||
|
@@ -324,7 +325,7 @@ compose_eap_identity_pkt(RADIUS_PACKET *
|
||||||
|
/*
|
||||||
|
* NAS IP address, Remote Access policy dictates this to be present
|
||||||
|
*/
|
||||||
|
- switch ((peap_instance.dst_addr)->sa_family) {
|
||||||
|
+ switch ((peap_instance.client_ip)->sa_family) {
|
||||||
|
|
||||||
|
case AF_INET:
|
||||||
|
|
||||||
|
@@ -340,7 +341,7 @@ compose_eap_identity_pkt(RADIUS_PACKET *
|
||||||
|
}
|
||||||
|
nas_tlv->type = PW_NAS_IP_ADDRESS;
|
||||||
|
nas_tlv->length = nas_tlv_size;
|
||||||
|
- nas_ip_addr = ((struct sockaddr_in *)peap_instance.dst_addr)->sin_addr.s_addr;
|
||||||
|
+ nas_ip_addr = ((struct sockaddr_in *)peap_instance.client_ip)->sin_addr.s_addr;
|
||||||
|
memcpy(nas_tlv->data, (uint32_t *) & nas_ip_addr, sizeof(uint32_t));
|
||||||
|
break;
|
||||||
|
|
||||||
|
@@ -358,7 +359,7 @@ compose_eap_identity_pkt(RADIUS_PACKET *
|
||||||
|
}
|
||||||
|
nas_tlv->type = PW_NAS_IPV6_ADDRESS;
|
||||||
|
nas_tlv->length = nas_tlv_size;
|
||||||
|
- nas_ipv6_addr = &(((struct sockaddr_in6 *)peap_instance.dst_addr)->sin6_addr.s6_addr);
|
||||||
|
+ nas_ipv6_addr = (uint8_t *) &(((struct sockaddr_in6 *)peap_instance.client_ip)->sin6_addr.s6_addr);
|
||||||
|
memcpy(nas_tlv->data, nas_ipv6_addr, IPV6_ADDR_SIZE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
@@ -729,7 +730,7 @@ compose_eap_packet(RADIUS_PACKET * req,
|
||||||
|
* NAS IP address, it is need in all packets as
|
||||||
|
* W2K3 server Remote Access policy is based on this
|
||||||
|
*/
|
||||||
|
- switch ((peap_instance.dst_addr)->sa_family) {
|
||||||
|
+ switch ((peap_instance.client_ip)->sa_family) {
|
||||||
|
|
||||||
|
case AF_INET:
|
||||||
|
|
||||||
|
@@ -741,11 +742,11 @@ compose_eap_packet(RADIUS_PACKET * req,
|
||||||
|
peap_log_debug(
|
||||||
|
"compose_eap_packet:Memory allocation failed,eap_msg is NULL\n");
|
||||||
|
CLEAN_UP();
|
||||||
|
- return -1;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
nas_tlv->type = PW_NAS_IP_ADDRESS;
|
||||||
|
nas_tlv->length = nas_tlv_size;
|
||||||
|
- nas_ip_addr = ((struct sockaddr_in *)peap_instance.dst_addr)->sin_addr.s_addr;
|
||||||
|
+ nas_ip_addr = ((struct sockaddr_in *)peap_instance.client_ip)->sin_addr.s_addr;
|
||||||
|
memcpy(nas_tlv->data, (uint32_t *) & nas_ip_addr, sizeof(uint32_t));
|
||||||
|
break;
|
||||||
|
|
||||||
|
@@ -759,11 +760,11 @@ compose_eap_packet(RADIUS_PACKET * req,
|
||||||
|
peap_log_debug(
|
||||||
|
"compose_eap_packet:Memory allocation failed,eap_msg is NULL\n");
|
||||||
|
CLEAN_UP();
|
||||||
|
- return -1;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
nas_tlv->type = PW_NAS_IPV6_ADDRESS;
|
||||||
|
nas_tlv->length = nas_tlv_size;
|
||||||
|
- nas_ipv6_addr = &(((struct sockaddr_in6 *)peap_instance.dst_addr)->sin6_addr.s6_addr);
|
||||||
|
+ nas_ipv6_addr = (uint8_t *) &(((struct sockaddr_in6 *)peap_instance.client_ip)->sin6_addr.s6_addr);
|
||||||
|
memcpy(nas_tlv->data, nas_ipv6_addr, IPV6_ADDR_SIZE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
@@ -1141,6 +1142,11 @@ rad_peap_send(RADIUS_PACKET * packet, co
|
||||||
|
|
||||||
|
sa = (struct sockaddr *) peap_instance.dst_addr;
|
||||||
|
|
||||||
|
+ _pam_radius_trace( peap_instance.conf, TRUE, sa,
|
||||||
|
+ (unsigned char *) packet->data, (int) packet->data_len);
|
||||||
|
+
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, packet->code);
|
||||||
|
+
|
||||||
|
#ifndef WITH_UDPFROMTO
|
||||||
|
return sendto(packet->sockfd, packet->data, (int) packet->data_len, 0,
|
||||||
|
(struct sockaddr *) sa,
|
||||||
|
@@ -1329,6 +1335,9 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ _pam_radius_trace( peap_instance.conf, FALSE, (struct sockaddr *) &saremote,
|
||||||
|
+ (unsigned char *) data, (int) packet->data_len);
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Fill IP header fields. We need these for the error
|
||||||
|
* messages which may come later.
|
||||||
|
@@ -1369,6 +1378,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
peap_log( LOG_ERR, "Malformed RADIUS packet from host %s:"
|
||||||
|
" too short (received %d < minimum %d)",
|
||||||
|
remote_ipaddr, packet->data_len, AUTH_HDR_LEN);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1383,6 +1393,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
" too long (received %d > maximum %d)",
|
||||||
|
remote_ipaddr,
|
||||||
|
packet->data_len, MAX_PACKET_LEN);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1405,6 +1416,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
" unknown packet code %d",
|
||||||
|
remote_ipaddr,
|
||||||
|
hdr->code);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1425,6 +1437,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
" too short (length %d < minimum %d)",
|
||||||
|
remote_ipaddr,
|
||||||
|
totallen, AUTH_HDR_LEN);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1441,6 +1454,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
" too long (length %d > maximum %d)",
|
||||||
|
remote_ipaddr,
|
||||||
|
totallen, MAX_PACKET_LEN);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1458,6 +1472,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
" received %d octets, packet length says %d",
|
||||||
|
remote_ipaddr,
|
||||||
|
packet->data_len, totallen);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1503,6 +1518,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
"Malformed RADIUS packet from host %s:"
|
||||||
|
" Invalid attribute 0",
|
||||||
|
remote_ipaddr);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1517,6 +1533,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
" attribute %d too short",
|
||||||
|
remote_ipaddr,
|
||||||
|
attr[0]);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1539,6 +1556,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
" Message-Authenticator has invalid length %d",
|
||||||
|
remote_ipaddr,
|
||||||
|
attr[1] - 2);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1567,6 +1585,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
"Malformed RADIUS packet from host %s:"
|
||||||
|
" packet attributes do NOT exactly fill the packet",
|
||||||
|
remote_ipaddr);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1583,6 +1602,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
" (received %d, max %d are allowed).",
|
||||||
|
remote_ipaddr,
|
||||||
|
num_attributes, librad_max_attributes);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1601,6 +1621,7 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
peap_log( LOG_ERR, "Insecure packet from host %s:"
|
||||||
|
" Received EAP-Message with no Message-Authenticator.",
|
||||||
|
remote_ipaddr);
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_INVALID_PACKET);
|
||||||
|
free(packet);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -1608,14 +1629,17 @@ static RADIUS_PACKET *rad_recv_ipv6(int
|
||||||
|
if ((hdr->code > 0) && (hdr->code < 52)) {
|
||||||
|
peap_log_debug("rad_recv: %s packet from host %s:%d",
|
||||||
|
packet_codes[hdr->code],
|
||||||
|
- remote_ipaddr);
|
||||||
|
+ remote_ipaddr, packet->src_port);
|
||||||
|
} else {
|
||||||
|
peap_log_debug("rad_recv: Packet from host %s:%d code=%d",
|
||||||
|
- remote_ipaddr,
|
||||||
|
+ remote_ipaddr, packet->src_port,
|
||||||
|
hdr->code);
|
||||||
|
}
|
||||||
|
peap_log_debug(", id=%d, length=%d\n", hdr->id, totallen);
|
||||||
|
|
||||||
|
+ if (hdr->code != PW_AUTHENTICATION_ACK)
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, hdr->code);
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Fill RADIUS header fields
|
||||||
|
*/
|
||||||
|
@@ -1665,6 +1689,7 @@ rad_peap_recv()
|
||||||
|
}
|
||||||
|
if ((rad_decode(rep, 0, peap_instance.shared_secret)) != 0) {
|
||||||
|
peap_log_debug("rad_peap_recv: rad_decode failed\n");
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_BAD_AUTHENTICATOR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
@@ -2472,8 +2497,10 @@ wait_for_server_response()
|
||||||
|
peap_log_debug("wait_for_server_response: Server timed out. peap_instance.retriesleft %d \n",
|
||||||
|
peap_instance.retries);
|
||||||
|
if (--(peap_instance.retries)) {
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_RETRY(STATS_AUTH_REQUEST));
|
||||||
|
return PEAP_SERVER_RETRY;
|
||||||
|
} else {
|
||||||
|
+ _pam_radius_incr( peap_instance.conf, STATS_TIMEOUT);
|
||||||
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -3203,6 +3230,11 @@ setup_client(const char * user_name, con
|
||||||
|
|
||||||
|
peap_instance.retries = conf->retries + 1;
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
+ * Set up peap_instance.client_ip from client_ip.
|
||||||
|
+ */
|
||||||
|
+ peap_instance.client_ip = conf->client_ip;
|
||||||
|
+
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
switch(cur_serv->ip->sa_family) {
|
||||||
|
@@ -3292,6 +3324,7 @@ pam_peap_authenticate(const char * user_
|
||||||
|
uint16_t rad_pkt_len = 0;
|
||||||
|
peap_instance.cur_serv = conf->server;
|
||||||
|
peap_instance.dst_addr = conf->server->ip;
|
||||||
|
+ peap_instance.conf = conf;
|
||||||
|
|
||||||
|
ret = setup_client(user_name, user_password, conf);
|
||||||
|
if (0 != ret) {
|
||||||
|
Index: pam_radius/src/radpeapclient.h
|
||||||
|
===================================================================
|
||||||
|
--- pam_radius.orig/src/radpeapclient.h
|
||||||
|
+++ pam_radius/src/radpeapclient.h
|
||||||
|
@@ -300,6 +300,8 @@ typedef struct _tls_data_list {
|
||||||
|
struct _tls_data_list * list_end;
|
||||||
|
} tls_data_list_t;
|
||||||
|
|
||||||
|
+struct radius_conf_t;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* The global data structure used for maintaining *all* the
|
||||||
|
* information needed at any point of time during the
|
||||||
|
@@ -312,6 +314,8 @@ typedef struct _peap_instance {
|
||||||
|
#endif
|
||||||
|
struct sockaddr *dst_addr;
|
||||||
|
struct sockaddr *src_addr;
|
||||||
|
+ struct sockaddr *client_ip;
|
||||||
|
+ struct radius_conf_t * conf;
|
||||||
|
int sockfd;
|
||||||
|
char * shared_secret;
|
||||||
|
char * user_name;
|
||||||
|
@@ -371,6 +375,8 @@ typedef struct radius_conf_t {
|
||||||
|
int retries;
|
||||||
|
int localifdown;
|
||||||
|
char *client_id;
|
||||||
|
+ struct sockaddr_storage client_ip_storage;
|
||||||
|
+ struct sockaddr *client_ip;
|
||||||
|
int accounting_bug;
|
||||||
|
int force_prompt;
|
||||||
|
int max_challenge;
|
||||||
|
@@ -383,6 +389,8 @@ typedef struct radius_conf_t {
|
||||||
|
int prompt_attribute;
|
||||||
|
int privilege_level;
|
||||||
|
int auth_type;
|
||||||
|
+ CONST char * trace; /* Packet Trace File */
|
||||||
|
+ CONST char * statistics; /* Statistics File */
|
||||||
|
} radius_conf_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Index: pam_radius/src/pam_radius_stats.c
|
||||||
|
===================================================================
|
||||||
|
--- /dev/null
|
||||||
|
+++ pam_radius/src/pam_radius_stats.c
|
||||||
|
@@ -0,0 +1,109 @@
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include <sys/file.h>
|
||||||
|
+#include <sys/types.h>
|
||||||
|
+#include <sys/socket.h>
|
||||||
|
+
|
||||||
|
+#include "pam_radius_auth.h"
|
||||||
|
+#include "pam_radius_stats.h"
|
||||||
|
+
|
||||||
|
+void _pam_radius_incr(radius_conf_t * conf, unsigned int index)
|
||||||
|
+{
|
||||||
|
+ unsigned long counters[STATS_MAX_COUNTER];
|
||||||
|
+ char statistics[MAX_RADIUS_STATS_PATHNAME_LEN];
|
||||||
|
+ FILE * fp;
|
||||||
|
+ int fd;
|
||||||
|
+ int retry_lock;
|
||||||
|
+
|
||||||
|
+ if (!conf||!conf->statistics||!index||(index >= STATS_MAX_COUNTER)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Open the file.
|
||||||
|
+ */
|
||||||
|
+ snprintf(statistics, sizeof(statistics), "%s/%s", STATISTICS_DIR,
|
||||||
|
+ conf->statistics);
|
||||||
|
+ statistics[sizeof(statistics) - 1] = 0;
|
||||||
|
+ if ((fp = fopen(statistics, "r+")) == NULL) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Lock the file.
|
||||||
|
+ */
|
||||||
|
+ fd = fileno(fp);
|
||||||
|
+ for (retry_lock = 3; retry_lock; retry_lock--) {
|
||||||
|
+ if (flock(fd, LOCK_EX|LOCK_NB) == 0)
|
||||||
|
+ break;
|
||||||
|
+ usleep(250*1000); /* quarter second */
|
||||||
|
+ }
|
||||||
|
+ if (!retry_lock) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Read
|
||||||
|
+ */
|
||||||
|
+ memset((char *) (&(counters[0])), 0, sizeof(counters));
|
||||||
|
+ fscanf(fp,
|
||||||
|
+ "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld "
|
||||||
|
+ "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld "
|
||||||
|
+ "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld "
|
||||||
|
+ "%ld %ld %ld %ld %ld %ld",
|
||||||
|
+ &(counters[0]), &(counters[1]), &(counters[2]), &(counters[3]),
|
||||||
|
+ &(counters[4]), &(counters[5]), &(counters[6]), &(counters[7]),
|
||||||
|
+ &(counters[8]), &(counters[9]), &(counters[10]), &(counters[11]),
|
||||||
|
+ &(counters[12]), &(counters[13]), &(counters[14]), &(counters[15]),
|
||||||
|
+ &(counters[16]), &(counters[17]), &(counters[18]), &(counters[19]),
|
||||||
|
+ &(counters[20]), &(counters[21]), &(counters[22]), &(counters[23]),
|
||||||
|
+ &(counters[24]), &(counters[25]), &(counters[26]), &(counters[27]),
|
||||||
|
+ &(counters[28]), &(counters[29]), &(counters[30]), &(counters[31]),
|
||||||
|
+ &(counters[32]), &(counters[33]), &(counters[34]), &(counters[35])
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
+ /* Increment
|
||||||
|
+ */
|
||||||
|
+ (counters[index])++;
|
||||||
|
+
|
||||||
|
+ /* Write
|
||||||
|
+ */
|
||||||
|
+ rewind(fp);
|
||||||
|
+ fprintf(fp,
|
||||||
|
+ "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld "
|
||||||
|
+ "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld "
|
||||||
|
+ "%ld %ld %ld %ld %ld %ld %ld %ld %ld %ld "
|
||||||
|
+ "%ld %ld %ld %ld %ld %ld",
|
||||||
|
+ (counters[0]), (counters[1]), (counters[2]), (counters[3]),
|
||||||
|
+ (counters[4]), (counters[5]), (counters[6]), (counters[7]),
|
||||||
|
+ (counters[8]), (counters[9]), (counters[10]), (counters[11]),
|
||||||
|
+ (counters[12]), (counters[13]), (counters[14]), (counters[15]),
|
||||||
|
+ (counters[16]), (counters[17]), (counters[18]), (counters[19]),
|
||||||
|
+ (counters[20]), (counters[21]), (counters[22]), (counters[23]),
|
||||||
|
+ (counters[24]), (counters[25]), (counters[26]), (counters[27]),
|
||||||
|
+ (counters[28]), (counters[29]), (counters[30]), (counters[31]),
|
||||||
|
+ (counters[32]), (counters[33]), (counters[34]), (counters[35])
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
+#if 0 /* Should be released on close */
|
||||||
|
+ flock(fd, LOCK_UN|LOCK_NB);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+ fclose(fp);
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#if defined(FOR_TESTING)
|
||||||
|
+
|
||||||
|
+radius_conf_t conf;
|
||||||
|
+
|
||||||
|
+int main(int ac, char * av[]) {
|
||||||
|
+
|
||||||
|
+ conf.statistics = "global";
|
||||||
|
+
|
||||||
|
+ _pam_radius_incr(&conf, STATS_AUTH_REQUEST);
|
||||||
|
+ _pam_radius_incr(&conf, STATS_RETRY(STATS_AUTH_REQUEST));
|
||||||
|
+ _pam_radius_incr(&conf, STATS_INVALID_PACKET);
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
Index: pam_radius/src/pam_radius_stats.h
|
||||||
|
===================================================================
|
||||||
|
--- /dev/null
|
||||||
|
+++ pam_radius/src/pam_radius_stats.h
|
||||||
|
@@ -0,0 +1,43 @@
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#if defined(FOR_TESTING)
|
||||||
|
+
|
||||||
|
+typedef struct radius_conf_t {
|
||||||
|
+ char * statistics; /* Statistics File */
|
||||||
|
+ char * trace; /* Trace File */
|
||||||
|
+} radius_conf_t;
|
||||||
|
+
|
||||||
|
+#define STATISTICS_DIR "."
|
||||||
|
+#define TRACE_DIR "."
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#ifndef STATISTICS_DIR
|
||||||
|
+#define STATISTICS_DIR "/etc/pam_radius_auth.d/statistics"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#ifndef TRACE_DIR
|
||||||
|
+#define TRACE_DIR "/var/log"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#define STATS_RETRY(code) (16+code)
|
||||||
|
+
|
||||||
|
+/* These are the same codes as in the RADIUS packet header */
|
||||||
|
+#define STATS_AUTH_REQUEST 1
|
||||||
|
+#define STATS_AUTH_ACK 2
|
||||||
|
+#define STATS_AUTH_REJECT 3
|
||||||
|
+
|
||||||
|
+#define STATS_TIMEOUT 32
|
||||||
|
+#define STATS_BAD_AUTHENTICATOR 33
|
||||||
|
+#define STATS_INVALID_PACKET 34
|
||||||
|
+#define STATS_MAX_COUNTER 36 /* Please change fscanf() fprintf() fmt */
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#define MAX_RADIUS_STATS_PATHNAME_LEN 256
|
||||||
|
+#define MAX_RADIUS_TRACE_PATHNAME_LEN 256
|
||||||
|
+
|
||||||
|
+void _pam_radius_incr(radius_conf_t * conf, unsigned int index);
|
||||||
|
+void _pam_radius_trace(radius_conf_t * conf, int send,
|
||||||
|
+ const struct sockaddr * addr, unsigned char * buf, int len);
|
||||||
|
Index: pam_radius/src/pam_radius_trace.c
|
||||||
|
===================================================================
|
||||||
|
--- /dev/null
|
||||||
|
+++ pam_radius/src/pam_radius_trace.c
|
||||||
|
@@ -0,0 +1,156 @@
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include <time.h>
|
||||||
|
+#include <ctype.h>
|
||||||
|
+
|
||||||
|
+#include <sys/file.h>
|
||||||
|
+#include <sys/types.h>
|
||||||
|
+#include <sys/socket.h>
|
||||||
|
+
|
||||||
|
+#include <arpa/inet.h>
|
||||||
|
+
|
||||||
|
+#include "pam_radius_auth.h"
|
||||||
|
+#include "pam_radius_stats.h"
|
||||||
|
+
|
||||||
|
+void _pam_radius_trace(radius_conf_t * conf, int send,
|
||||||
|
+ const struct sockaddr * addr, unsigned char * buf, int len)
|
||||||
|
+{
|
||||||
|
+ FILE * fp;
|
||||||
|
+ char trace[MAX_RADIUS_TRACE_PATHNAME_LEN];
|
||||||
|
+ int fd;
|
||||||
|
+ int retry_lock;
|
||||||
|
+#define CTIME_BUFSIZE (26+10) /* GNU library says 26 chars is enough */
|
||||||
|
+ char ctime_buf[CTIME_BUFSIZE];
|
||||||
|
+ time_t current_time = 0;
|
||||||
|
+ char ipVx[ INET6_ADDRSTRLEN + 1 ];
|
||||||
|
+ int ct, idx;
|
||||||
|
+ unsigned int port = 0;
|
||||||
|
+ char port_str[sizeof(":65535")+1];
|
||||||
|
+
|
||||||
|
+ if (!conf->trace || (len < 0)) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Open the file.
|
||||||
|
+ */
|
||||||
|
+ snprintf(trace, sizeof(trace), "%s/%s", TRACE_DIR, conf->trace);
|
||||||
|
+ trace[sizeof(trace) - 1] = 0;
|
||||||
|
+ if ((fp = fopen(trace, "a")) == NULL) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Lock the file.
|
||||||
|
+ */
|
||||||
|
+ fd = fileno(fp);
|
||||||
|
+ for (retry_lock = 3; retry_lock; retry_lock--) {
|
||||||
|
+ if (flock(fd, LOCK_EX|LOCK_NB) == 0)
|
||||||
|
+ break;
|
||||||
|
+ usleep(250*1000); /* quarter second */
|
||||||
|
+ }
|
||||||
|
+ if (!retry_lock) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Current Time
|
||||||
|
+ */
|
||||||
|
+ time(¤t_time);
|
||||||
|
+ ctime_buf[0] = 0;
|
||||||
|
+ ctime_r(¤t_time, ctime_buf);
|
||||||
|
+
|
||||||
|
+ /* Remote Peer
|
||||||
|
+ */
|
||||||
|
+ memset(ipVx, 0, sizeof(ipVx));
|
||||||
|
+ if (addr && (addr->sa_family == AF_INET)) {
|
||||||
|
+ strncpy(ipVx,
|
||||||
|
+ inet_ntoa(((struct sockaddr_in *) addr)->sin_addr),
|
||||||
|
+ sizeof(ipVx) - 1);
|
||||||
|
+ port = ntohs(((struct sockaddr_in *) addr)->sin_port);
|
||||||
|
+ } else if (addr && (addr->sa_family == AF_INET6)) {
|
||||||
|
+ strncpy(ipVx,
|
||||||
|
+ inet_ntop(AF_INET6,
|
||||||
|
+ &(((struct sockaddr_in6 *) addr)->sin6_addr),
|
||||||
|
+ ipVx, sizeof(ipVx)),
|
||||||
|
+ sizeof(ipVx) - 1);
|
||||||
|
+ port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ memset(port_str, 0, sizeof(port_str));
|
||||||
|
+ if (port)
|
||||||
|
+ snprintf(port_str, sizeof(port_str) -1, ":%d", port);
|
||||||
|
+
|
||||||
|
+ /* Write Summary
|
||||||
|
+ */
|
||||||
|
+ fprintf(fp, "[%ld] %s [%s]%s %s", (long) getpid(),
|
||||||
|
+ (send ? "Sending to" : "Received from"),
|
||||||
|
+ ipVx, port_str, ctime_buf);
|
||||||
|
+
|
||||||
|
+ /* Write Packet
|
||||||
|
+ */
|
||||||
|
+ for(ct = 0; ct < len ; ct += 16) {
|
||||||
|
+ fprintf( fp, "[%ld]", (long) getpid());
|
||||||
|
+ for (idx = 0; ((ct + idx) < len) && (idx < 16); idx++) {
|
||||||
|
+ if (idx && ((idx % 8) == 0))
|
||||||
|
+ fprintf( fp, " ");
|
||||||
|
+ fprintf( fp, " %02x", (buf[ct + idx]));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for ( ; idx < 16 ; idx++) {
|
||||||
|
+ if (idx && ((idx % 8) == 0))
|
||||||
|
+ fprintf( fp, " ");
|
||||||
|
+ fprintf( fp, " ");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (idx = 0; ((ct + idx) < len) && (idx < 16); idx++) {
|
||||||
|
+ if ((idx % 8) == 0)
|
||||||
|
+ fprintf( fp, " ");
|
||||||
|
+ if (isprint(buf[ct + idx]) && !isspace(buf[ct + idx]))
|
||||||
|
+ fprintf( fp, "%c", buf[ct + idx]);
|
||||||
|
+ else
|
||||||
|
+ fprintf( fp, ".");
|
||||||
|
+ }
|
||||||
|
+ fprintf( fp, "\n");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ fprintf( fp, "\n");
|
||||||
|
+
|
||||||
|
+#if 0 /* Should be released on close */
|
||||||
|
+ flock(fd, LOCK_UN|LOCK_NB);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+ fclose(fp);
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#if defined(FOR_TESTING)
|
||||||
|
+
|
||||||
|
+radius_conf_t conf;
|
||||||
|
+
|
||||||
|
+int main(int ac, char * av[]) {
|
||||||
|
+
|
||||||
|
+ struct sockaddr_in sa;
|
||||||
|
+ struct sockaddr_in6 sa6;
|
||||||
|
+
|
||||||
|
+ conf.statistics = "global";
|
||||||
|
+ conf.trace = "packettrace";
|
||||||
|
+
|
||||||
|
+ _pam_radius_trace(&conf, 1, NULL, (conf.statistics), strlen(conf.statistics));
|
||||||
|
+ _pam_radius_trace(&conf, 0, NULL, (conf.trace), strlen(conf.trace));
|
||||||
|
+
|
||||||
|
+ memset(&sa, 0, sizeof(sa));
|
||||||
|
+ memset(&sa6, 0, sizeof(sa6));
|
||||||
|
+ ((struct sockaddr *)&sa)->sa_family = AF_INET;
|
||||||
|
+ ((struct sockaddr *)&sa6)->sa_family = AF_INET6;
|
||||||
|
+ inet_pton(AF_INET, "10.25.1.2", &(sa.sin_addr));
|
||||||
|
+ inet_pton(AF_INET6, "::1", &(sa6.sin6_addr));
|
||||||
|
+ sa.sin_port = htons(1812);
|
||||||
|
+ sa6.sin6_port = htons(1812);
|
||||||
|
+
|
||||||
|
+ _pam_radius_trace(&conf, 1, (struct sockaddr *) &sa, "0123456789012345678901234567890123", 34);
|
||||||
|
+ _pam_radius_trace(&conf, 0, (struct sockaddr *) &sa6, "0123456789012345678901234567890123", 34);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
Index: pam_radius/pam_radius
|
||||||
|
===================================================================
|
||||||
|
--- /dev/null
|
||||||
|
+++ pam_radius/pam_radius
|
||||||
|
@@ -0,0 +1,9 @@
|
||||||
|
+/var/log/pam_radius_trace.log
|
||||||
|
+{
|
||||||
|
+ size 1M
|
||||||
|
+ rotate 8
|
||||||
|
+ missingok
|
||||||
|
+ notifempty
|
||||||
|
+ compress
|
||||||
|
+ delaycompress
|
||||||
|
+}
|
||||||
|
Index: pam_radius/Makefile
|
||||||
|
===================================================================
|
||||||
|
--- pam_radius.orig/Makefile
|
||||||
|
+++ pam_radius/Makefile
|
||||||
|
@@ -63,6 +63,12 @@ src/mschapv2.o: src/mschapv2.c
|
||||||
|
src/radpeapclient.o: src/radpeapclient.c src/radpeapclient.h
|
||||||
|
@$(MAKE) -C src $(notdir $@)
|
||||||
|
|
||||||
|
+src/pam_radius_stats.o: src/pam_radius_stats.c src/pam_radius_stats.h src/pam_radius_auth.h
|
||||||
|
+ @$(MAKE) -C src $(notdir $@)
|
||||||
|
+
|
||||||
|
+src/pam_radius_trace.o: src/pam_radius_trace.c src/pam_radius_stats.h src/pam_radius_auth.h
|
||||||
|
+ @$(MAKE) -C src $(notdir $@)
|
||||||
|
+
|
||||||
|
#
|
||||||
|
# This is what should work on Irix:
|
||||||
|
#pam_radius_auth.so: pam_radius_auth.o md5.o
|
||||||
|
@@ -81,7 +87,7 @@ src/radpeapclient.o: src/radpeapclient.c
|
||||||
|
#
|
||||||
|
# gcc -shared pam_radius_auth.o md5.o -lpam -lc -o pam_radius_auth.so
|
||||||
|
#
|
||||||
|
-pam_radius_auth.so: src/pam_radius_auth.o src/md5.o src/mschapv2.o src/radpeapclient.o
|
||||||
|
+pam_radius_auth.so: src/pam_radius_auth.o src/md5.o src/mschapv2.o src/radpeapclient.o src/pam_radius_stats.o src/pam_radius_trace.o
|
||||||
|
$(CC) $(LDFLAGS) $^ -lpam -lradius-1.1.8 -leap-1.1.8 -lssl -o pam_radius_auth.so
|
||||||
|
|
||||||
|
######################################################################
|
3
src/radius/pam/patches/series
Normal file
3
src/radius/pam/patches/series
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
0001-chap-support.patch
|
||||||
|
0002-peap-mschapv2-support.patch
|
||||||
|
0003-nas-ip-address-config.patch
|
@ -15,6 +15,7 @@ build:
|
|||||||
override_dh_installsystemd:
|
override_dh_installsystemd:
|
||||||
dh_installsystemd --no-start --name=caclmgrd
|
dh_installsystemd --no-start --name=caclmgrd
|
||||||
dh_installsystemd --no-start --name=hostcfgd
|
dh_installsystemd --no-start --name=hostcfgd
|
||||||
|
dh_installsystemd --no-start --name=aaastatsd
|
||||||
dh_installsystemd --no-start --name=procdockerstatsd
|
dh_installsystemd --no-start --name=procdockerstatsd
|
||||||
dh_installsystemd --no-start --name=determine-reboot-cause
|
dh_installsystemd --no-start --name=determine-reboot-cause
|
||||||
dh_installsystemd --no-start --name=process-reboot-cause
|
dh_installsystemd --no-start --name=process-reboot-cause
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=AAA Statistics Collection daemon
|
||||||
|
Requires=hostcfgd.service
|
||||||
|
After=hostcfgd.service updategraph.service
|
||||||
|
BindsTo=sonic.target
|
||||||
|
After=sonic.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/usr/local/bin/aaastatsd
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
TimeoutStopSec=3
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=sonic.target
|
||||||
|
|
@ -28,6 +28,42 @@ auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
auth [success=1 default=ignore] pam_unix.so nullok try_first_pass
|
auth [success=1 default=ignore] pam_unix.so nullok try_first_pass
|
||||||
|
|
||||||
|
{% elif auth['login'] == 'local,radius' %}
|
||||||
|
auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die maxtries=die' if not auth['failthrough'] }}] pam_unix.so nullok try_first_pass
|
||||||
|
# For the RADIUS servers, on success jump to the cacheing the MPL(Privilege)
|
||||||
|
{% for server in servers %}
|
||||||
|
auth [success={{ (servers | count) - loop.index0 }} new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not auth['failthrough'] }}] pam_radius_auth.so conf=/etc/pam_radius_auth.d/{{ server.ip }}:{{ server.auth_port }}.conf privilege_level protocol={{ server.auth_type }} retry={{ server.retransmit }}{% if server.nas_ip is defined %} nas_ip_address={{ server.nas_ip }}{% endif %}{% if server.nas_id is defined %} client_id={{ server.nas_id }}{% endif %}{% if debug %} debug{% endif %}{% if trace %} trace{% endif %}{% if server.statistics %} statistics={{ server.ip }}{% endif %} try_first_pass
|
||||||
|
{% endfor %}
|
||||||
|
auth requisite pam_deny.so
|
||||||
|
# Cache MPL(Privilege)
|
||||||
|
auth [success=1 default=ignore] pam_exec.so /usr/sbin/cache_radius
|
||||||
|
|
||||||
|
{% elif auth['login'] == 'radius,local' %}
|
||||||
|
# root user can only be authenticated locally. Jump to local.
|
||||||
|
auth [success={{ (servers | count) }} default=ignore] pam_succeed_if.so user = root
|
||||||
|
# For the RADIUS servers, on success jump to the cache the MPL(Privilege)
|
||||||
|
{% for server in servers %}
|
||||||
|
auth [success={{ (servers | count) + 1 - loop.index0 }} new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not auth['failthrough'] }}] pam_radius_auth.so conf=/etc/pam_radius_auth.d/{{ server.ip }}:{{ server.auth_port }}.conf privilege_level protocol={{ server.auth_type }} retry={{ server.retransmit }}{% if server.nas_ip is defined %} nas_ip_address={{ server.nas_ip }}{% endif %}{% if server.nas_id is defined %} client_id={{ server.nas_id }}{% endif %}{% if debug %} debug{% endif %}{% if trace %} trace{% endif %}{% if server.statistics %} statistics={{ server.ip }}{% endif %} try_first_pass
|
||||||
|
{% endfor %}
|
||||||
|
# Local
|
||||||
|
auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die maxtries=die' if not auth['failthrough'] }}] pam_unix.so nullok try_first_pass
|
||||||
|
auth requisite pam_deny.so
|
||||||
|
# Cache MPL(Privilege)
|
||||||
|
auth [success=1 default=ignore] pam_exec.so /usr/sbin/cache_radius
|
||||||
|
|
||||||
|
{% elif auth['login'] == 'radius' %}
|
||||||
|
# root user can only be authenticated locally. Jump to local.
|
||||||
|
auth [success={{ (servers | count) + 2 }} default=ignore] pam_succeed_if.so user = root
|
||||||
|
# For the RADIUS servers, on success jump to the cache the MPL(Privilege)
|
||||||
|
{% for server in servers %}
|
||||||
|
auth [success={{ (servers | count) - loop.index0 }} new_authtok_reqd=done default=ignore{{ ' auth_err=die' if not auth['failthrough'] }}] pam_radius_auth.so conf=/etc/pam_radius_auth.d/{{ server.ip }}:{{ server.auth_port }}.conf privilege_level protocol={{ server.auth_type }} retry={{ server.retransmit }}{% if server.nas_ip is defined %} nas_ip_address={{ server.nas_ip }}{% endif %}{% if server.nas_id is defined %} client_id={{ server.nas_id }}{% endif %}{% if debug %} debug{% endif %}{% if trace %} trace{% endif %}{% if server.statistics %} statistics={{ server.ip }}{% endif %} try_first_pass
|
||||||
|
{% endfor %}
|
||||||
|
auth requisite pam_deny.so
|
||||||
|
# Cache MPL(Privilege)
|
||||||
|
auth [success=2 default=ignore] pam_exec.so /usr/sbin/cache_radius
|
||||||
|
# Local
|
||||||
|
auth [success=done new_authtok_reqd=done default=ignore{{ ' auth_err=die maxtries=die' if not auth['failthrough'] }}] pam_unix.so nullok try_first_pass
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
auth [success=1 default=ignore] pam_unix.so nullok try_first_pass
|
auth [success=1 default=ignore] pam_unix.so nullok try_first_pass
|
||||||
|
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
# server[:port] shared_secret timeout(s) source_ip vrf
|
||||||
|
[{{ server.ip }}]:{{ server.auth_port }} {{ server.passkey }} {{ server.timeout }} {% if server.src_ip %} {{ server.src_ip }} {% endif %} {% if server.vrf %} {% if not server.src_ip %} - {% endif %} {{ server.vrf }}{% endif %}
|
||||||
|
|
58
src/sonic-host-services-data/templates/radius_nss.conf.j2
Normal file
58
src/sonic-host-services-data/templates/radius_nss.conf.j2
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#THIS IS AN AUTO-GENERATED FILE
|
||||||
|
# Generated from: /usr/share/sonic/templates/radius_nss.conf.j2
|
||||||
|
# RADIUS NSS Configuration File
|
||||||
|
#
|
||||||
|
# Debug: on|off|trace
|
||||||
|
# Default: off
|
||||||
|
#
|
||||||
|
# debug=on
|
||||||
|
{% if debug %}
|
||||||
|
debug=on
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
#
|
||||||
|
# User Privilege:
|
||||||
|
# Default:
|
||||||
|
# user_priv=15;pw_info=remote_user_su;gid=1000;group=sudo,docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=1;pw_info=remote_user;gid=999;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# user_priv=15;pw_info=remote_user_su;gid=1000;group=sudo,docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=7;pw_info=netops;gid=999;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=1;pw_info=operator;gid=100;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
#
|
||||||
|
|
||||||
|
# many_to_one:
|
||||||
|
# y: Map RADIUS users to one local user per privilege.
|
||||||
|
# n: Create local user account on first successful authentication.
|
||||||
|
# Default: n
|
||||||
|
#
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# many_to_one=y
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_disallow:
|
||||||
|
# y: Do not allow unconfirmed users (users created before authentication)
|
||||||
|
# n: Allow unconfirmed users.
|
||||||
|
# Default: n
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# unconfirmed_disallow=y
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_ageout:
|
||||||
|
# <seconds>: Wait time before purging unconfirmed users
|
||||||
|
# Default: 600
|
||||||
|
#
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# unconfirmed_ageout=900
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_regexp:
|
||||||
|
# <regexp>: The RE to match the command line of processes for which the
|
||||||
|
# creation of unconfirmed users are to be allowed.
|
||||||
|
# Default: (.*: <user> \[priv\])|(.*: \[accepted\])
|
||||||
|
# where: <user> is the unconfirmed user.
|
||||||
|
#
|
5
src/sonic-host-services/.gitignore
vendored
5
src/sonic-host-services/.gitignore
vendored
@ -2,6 +2,7 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
scripts/caclmgrdc
|
scripts/caclmgrdc
|
||||||
scripts/hostcfgdc
|
scripts/hostcfgdc
|
||||||
|
scripts/aaastatsdc
|
||||||
scripts/procdockerstatsdc
|
scripts/procdockerstatsdc
|
||||||
|
|
||||||
# Generated by packaging
|
# Generated by packaging
|
||||||
@ -15,3 +16,7 @@ dist/
|
|||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
coverage.xml
|
coverage.xml
|
||||||
htmlcov/
|
htmlcov/
|
||||||
|
test-results.xml
|
||||||
|
|
||||||
|
# Unit test scratchpad
|
||||||
|
tests/hostcfgd/output/*
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
[pytest]
|
[pytest]
|
||||||
addopts = --cov=scripts --cov-report html --cov-report term --cov-report xml --ignore=tests/hostcfgd/test_vectors.py
|
addopts = --cov=scripts --cov-report html --cov-report term --cov-report xml --ignore=tests/hostcfgd/test_vectors.py --ignore=tests/hostcfgd/test_radius_vectors.py
|
||||||
|
222
src/sonic-host-services/scripts/aaastatsd
Executable file
222
src/sonic-host-services/scripts/aaastatsd
Executable file
@ -0,0 +1,222 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import syslog
|
||||||
|
import threading
|
||||||
|
from swsssdk import ConfigDBConnector
|
||||||
|
from watchdog.observers import Observer
|
||||||
|
from watchdog.events import FileSystemEventHandler
|
||||||
|
|
||||||
|
# FILE
|
||||||
|
RADIUS_PAM_AUTH_CONF_DIR = "/etc/pam_radius_auth.d/"
|
||||||
|
RADIUS_PAM_AUTH_CONF_STATS_DIR = "/etc/pam_radius_auth.d/statistics/"
|
||||||
|
|
||||||
|
class RadiusCountersDbMon (threading.Thread):
|
||||||
|
def __init__(self, ID, name, radiusStatsInstance):
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.ID = ID
|
||||||
|
self.name = name
|
||||||
|
self.radiusStatsInstance = radiusStatsInstance
|
||||||
|
|
||||||
|
def handle_CountersDbRadiusClear(self, key, data):
|
||||||
|
# print("RadiusCountersDbMon.handle_CountersDbRadiusClear()")
|
||||||
|
if key == 'clear':
|
||||||
|
self.radiusStatsInstance.handle_clear()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# print("RadiusCountersDbMon.run()")
|
||||||
|
self.radiusStatsInstance.counters_db.subscribe('RADIUS', lambda table, key, data: self.handle_CountersDbRadiusClear(key, data))
|
||||||
|
self.radiusStatsInstance.counters_db.listen()
|
||||||
|
# print("RadiusCountersDbMon.run(): After listen()")
|
||||||
|
|
||||||
|
|
||||||
|
class RadiusStatsFileHandler(FileSystemEventHandler):
|
||||||
|
def __init__(self, radiusStatsInstance):
|
||||||
|
self.radiusStatsInstance = radiusStatsInstance
|
||||||
|
|
||||||
|
def on_any_event(self, event):
|
||||||
|
# print("RadiusStatsFileHandler.on_any_event()")
|
||||||
|
if event.is_directory:
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.radiusStatsInstance.handle_update(os.path.basename(event.src_path))
|
||||||
|
|
||||||
|
class RadiusStatsFileMon ():
|
||||||
|
def __init__(self, radiusStatsInstance):
|
||||||
|
self.event_handler = RadiusStatsFileHandler(radiusStatsInstance)
|
||||||
|
self.observer = Observer()
|
||||||
|
self.observer.schedule(self.event_handler, RADIUS_PAM_AUTH_CONF_STATS_DIR, recursive=False)
|
||||||
|
self.observer.start()
|
||||||
|
# print("RadiusStatsFileMon.__init__(): After observer.start()")
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
# print("RadiusStatsFileMon.stop()")
|
||||||
|
self.observer.stop()
|
||||||
|
# print("RadiusStatsFileMon.stop(): After observer.stop()")
|
||||||
|
self.observer.join()
|
||||||
|
# print("RadiusStatsFileMon.stop(): After observer.join()")
|
||||||
|
|
||||||
|
|
||||||
|
class RadiusStatistics:
|
||||||
|
def __init__(self, cfg_db, rad_global_conf, radius_conf):
|
||||||
|
|
||||||
|
self.radius_counter_names = [
|
||||||
|
"counter_0",
|
||||||
|
"access_requests",
|
||||||
|
"access_accepts",
|
||||||
|
"access_rejects",
|
||||||
|
"accounting_requests",
|
||||||
|
"accounting_responses",
|
||||||
|
"counter_6",
|
||||||
|
"counter_7",
|
||||||
|
"counter_8",
|
||||||
|
"counter_9",
|
||||||
|
"counter_10",
|
||||||
|
"access_challenges",
|
||||||
|
"counter_12",
|
||||||
|
"counter_13",
|
||||||
|
"counter_14",
|
||||||
|
"counter_15",
|
||||||
|
"counter_16",
|
||||||
|
"retried_access_requests",
|
||||||
|
"counter_18",
|
||||||
|
"counter_19",
|
||||||
|
"retried_accounting_requests",
|
||||||
|
"counter_21",
|
||||||
|
"counter_22",
|
||||||
|
"counter_23",
|
||||||
|
"counter_24",
|
||||||
|
"counter_25",
|
||||||
|
"counter_26",
|
||||||
|
"retried_access_challenges",
|
||||||
|
"counter_28",
|
||||||
|
"counter_29",
|
||||||
|
"counter_30",
|
||||||
|
"counter_31",
|
||||||
|
"timeouts",
|
||||||
|
"bad_authenticators",
|
||||||
|
"invalid_packets",
|
||||||
|
"counter_35",
|
||||||
|
]
|
||||||
|
|
||||||
|
self.radius_global = {
|
||||||
|
'statistics': 'False'
|
||||||
|
}
|
||||||
|
|
||||||
|
self.radius_servers = {}
|
||||||
|
|
||||||
|
self.config_db = cfg_db
|
||||||
|
|
||||||
|
for row in rad_global_conf:
|
||||||
|
self.radius_global_update(row, rad_global_conf[row])
|
||||||
|
|
||||||
|
for row in radius_conf:
|
||||||
|
self.radius_server_update(row, radius_conf[row])
|
||||||
|
|
||||||
|
|
||||||
|
self.counters_db = ConfigDBConnector()
|
||||||
|
self.counters_db.db_connect('COUNTERS_DB', wait_for_init=False,
|
||||||
|
retry_on=True)
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'CountersDB connect success')
|
||||||
|
self.dbmon_thread = RadiusCountersDbMon("RadiusCountersDbMon",
|
||||||
|
"RadiusCountersDbMon", self)
|
||||||
|
self.dbmon_thread.daemon = True
|
||||||
|
self.dbmon_thread.start()
|
||||||
|
|
||||||
|
self.filemon = RadiusStatsFileMon(self)
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'RADIUS Stats File Monitor started')
|
||||||
|
|
||||||
|
def radius_global_update(self, key, data):
|
||||||
|
if key == 'global':
|
||||||
|
self.radius_global.update(data)
|
||||||
|
|
||||||
|
for addr in self.radius_servers:
|
||||||
|
self.create_file(addr)
|
||||||
|
|
||||||
|
def radius_server_update(self, key, data):
|
||||||
|
if data == {}:
|
||||||
|
if key in self.radius_servers:
|
||||||
|
del self.radius_servers[key]
|
||||||
|
else:
|
||||||
|
self.radius_servers[key] = data
|
||||||
|
|
||||||
|
self.create_file(key)
|
||||||
|
|
||||||
|
def create_file(self, addr):
|
||||||
|
# print( "RadiusStatistics.create_file({})".format(addr))
|
||||||
|
stats_file = RADIUS_PAM_AUTH_CONF_STATS_DIR + addr
|
||||||
|
if self.radius_global['statistics'] == 'False':
|
||||||
|
if os.path.exists(stats_file):
|
||||||
|
os.unlink(stats_file)
|
||||||
|
else:
|
||||||
|
open(stats_file, 'a').close()
|
||||||
|
os.chmod(stats_file, 0o666)
|
||||||
|
self.handle_update(addr)
|
||||||
|
|
||||||
|
def handle_clear(self):
|
||||||
|
# print( "RadiusStatistics.handle_clear()")
|
||||||
|
for filename in os.listdir(RADIUS_PAM_AUTH_CONF_STATS_DIR):
|
||||||
|
stats_file = RADIUS_PAM_AUTH_CONF_STATS_DIR + filename
|
||||||
|
open(stats_file, 'w').close()
|
||||||
|
|
||||||
|
def handle_update(self, srv):
|
||||||
|
# print( "RadiusStatistics.handle_update({})".format(srv))
|
||||||
|
if self.radius_global['statistics'] == 'False':
|
||||||
|
return
|
||||||
|
|
||||||
|
stats_file = RADIUS_PAM_AUTH_CONF_STATS_DIR + srv
|
||||||
|
entry = None
|
||||||
|
if os.path.exists(stats_file):
|
||||||
|
with open(stats_file, 'r') as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
if len(lines) > 0:
|
||||||
|
radius_counters = lines[0].split(' ')
|
||||||
|
entry = dict(zip(self.radius_counter_names, radius_counters))
|
||||||
|
|
||||||
|
counters_db = ConfigDBConnector()
|
||||||
|
counters_db.db_connect('COUNTERS_DB', wait_for_init=False,
|
||||||
|
retry_on=False)
|
||||||
|
|
||||||
|
counters_db.set_entry('RADIUS_SERVER_STATS', srv, entry)
|
||||||
|
|
||||||
|
counters_db.close(counters_db.COUNTERS_DB)
|
||||||
|
|
||||||
|
class AAAStatsDaemon:
|
||||||
|
def __init__(self):
|
||||||
|
self.config_db = ConfigDBConnector()
|
||||||
|
self.config_db.connect(wait_for_init=True, retry_on=True)
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'ConfigDB connect success')
|
||||||
|
|
||||||
|
radius_global = self.config_db.get_table('RADIUS')
|
||||||
|
radius_server = self.config_db.get_table('RADIUS_SERVER')
|
||||||
|
|
||||||
|
self.radiusstats = RadiusStatistics(self.config_db, radius_global,
|
||||||
|
radius_server)
|
||||||
|
|
||||||
|
def radius_global_handler(self, key, data):
|
||||||
|
self.radiusstats.radius_global_update(key, data)
|
||||||
|
|
||||||
|
def radius_server_handler(self, key, data):
|
||||||
|
self.radiusstats.radius_server_update(key, data)
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self.config_db.subscribe('RADIUS_SERVER',
|
||||||
|
lambda table, key, data: self.radius_server_handler(key, data))
|
||||||
|
self.config_db.subscribe('RADIUS',
|
||||||
|
lambda table, key, data: self.radius_global_handler(key, data))
|
||||||
|
self.config_db.listen()
|
||||||
|
# print( "After config_db.listen()")
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'Stopping FileMon')
|
||||||
|
self.radiusstats.filemon.stop()
|
||||||
|
# print( "Exiting")
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'Exiting')
|
||||||
|
|
||||||
|
def main():
|
||||||
|
daemon = AAAStatsDaemon()
|
||||||
|
daemon.start()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -16,20 +16,25 @@ PAM_AUTH_CONF = "/etc/pam.d/common-auth-sonic"
|
|||||||
PAM_AUTH_CONF_TEMPLATE = "/usr/share/sonic/templates/common-auth-sonic.j2"
|
PAM_AUTH_CONF_TEMPLATE = "/usr/share/sonic/templates/common-auth-sonic.j2"
|
||||||
NSS_TACPLUS_CONF = "/etc/tacplus_nss.conf"
|
NSS_TACPLUS_CONF = "/etc/tacplus_nss.conf"
|
||||||
NSS_TACPLUS_CONF_TEMPLATE = "/usr/share/sonic/templates/tacplus_nss.conf.j2"
|
NSS_TACPLUS_CONF_TEMPLATE = "/usr/share/sonic/templates/tacplus_nss.conf.j2"
|
||||||
|
NSS_RADIUS_CONF = "/etc/radius_nss.conf"
|
||||||
|
NSS_RADIUS_CONF_TEMPLATE = "/usr/share/sonic/templates/radius_nss.conf.j2"
|
||||||
|
PAM_RADIUS_AUTH_CONF_TEMPLATE = "/usr/share/sonic/templates/pam_radius_auth.conf.j2"
|
||||||
NSS_CONF = "/etc/nsswitch.conf"
|
NSS_CONF = "/etc/nsswitch.conf"
|
||||||
|
ETC_PAMD_SSHD = "/etc/pam.d/sshd"
|
||||||
|
ETC_PAMD_LOGIN = "/etc/pam.d/login"
|
||||||
|
|
||||||
# TACACS+
|
# TACACS+
|
||||||
TACPLUS_SERVER_PASSKEY_DEFAULT = ""
|
TACPLUS_SERVER_PASSKEY_DEFAULT = ""
|
||||||
TACPLUS_SERVER_TIMEOUT_DEFAULT = "5"
|
TACPLUS_SERVER_TIMEOUT_DEFAULT = "5"
|
||||||
TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap"
|
TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap"
|
||||||
|
|
||||||
def run_cmd(cmd, log_err = True):
|
# RADIUS
|
||||||
try:
|
RADIUS_SERVER_AUTH_PORT_DEFAULT = "1812"
|
||||||
subprocess.check_call(cmd, shell = True)
|
RADIUS_SERVER_PASSKEY_DEFAULT = ""
|
||||||
except Exception as err:
|
RADIUS_SERVER_RETRANSMIT_DEFAULT = "3"
|
||||||
if log_err:
|
RADIUS_SERVER_TIMEOUT_DEFAULT = "5"
|
||||||
syslog.syslog(syslog.LOG_ERR, "{} - failed: return code - {}, output:\n{}"
|
RADIUS_SERVER_AUTH_TYPE_DEFAULT = "pap"
|
||||||
.format(err.cmd, err.returncode, err.output))
|
RADIUS_PAM_AUTH_CONF_DIR = "/etc/pam_radius_auth.d/"
|
||||||
|
|
||||||
def is_true(val):
|
def is_true(val):
|
||||||
if val == 'True' or val == 'true':
|
if val == 'True' or val == 'true':
|
||||||
@ -37,6 +42,9 @@ def is_true(val):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def is_vlan_sub_interface(ifname):
|
||||||
|
ifname_split = ifname.split(".")
|
||||||
|
return (len(ifname_split) == 2)
|
||||||
|
|
||||||
def sub(l, start, end):
|
def sub(l, start, end):
|
||||||
return l[start:end]
|
return l[start:end]
|
||||||
@ -56,6 +64,8 @@ def run_cmd(cmd, log_err = True):
|
|||||||
if log_err:
|
if log_err:
|
||||||
syslog.syslog(syslog.LOG_ERR, "{} - failed: return code - {}, output:\n{}"
|
syslog.syslog(syslog.LOG_ERR, "{} - failed: return code - {}, output:\n{}"
|
||||||
.format(err.cmd, err.returncode, err.output))
|
.format(err.cmd, err.returncode, err.output))
|
||||||
|
return err.returncode
|
||||||
|
return 0
|
||||||
|
|
||||||
class Iptables(object):
|
class Iptables(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -144,19 +154,40 @@ class AaaCfg(object):
|
|||||||
'timeout': TACPLUS_SERVER_TIMEOUT_DEFAULT,
|
'timeout': TACPLUS_SERVER_TIMEOUT_DEFAULT,
|
||||||
'passkey': TACPLUS_SERVER_PASSKEY_DEFAULT
|
'passkey': TACPLUS_SERVER_PASSKEY_DEFAULT
|
||||||
}
|
}
|
||||||
self.auth = {}
|
|
||||||
self.tacplus_global = {}
|
self.tacplus_global = {}
|
||||||
self.tacplus_servers = {}
|
self.tacplus_servers = {}
|
||||||
|
|
||||||
|
self.radius_global_default = {
|
||||||
|
'priority': 0,
|
||||||
|
'auth_port': RADIUS_SERVER_AUTH_PORT_DEFAULT,
|
||||||
|
'auth_type': RADIUS_SERVER_AUTH_TYPE_DEFAULT,
|
||||||
|
'retransmit': RADIUS_SERVER_RETRANSMIT_DEFAULT,
|
||||||
|
'timeout': RADIUS_SERVER_TIMEOUT_DEFAULT,
|
||||||
|
'passkey': RADIUS_SERVER_PASSKEY_DEFAULT
|
||||||
|
}
|
||||||
|
self.radius_global = {}
|
||||||
|
self.radius_servers = {}
|
||||||
|
|
||||||
|
self.auth = {}
|
||||||
self.debug = False
|
self.debug = False
|
||||||
|
self.trace = False
|
||||||
|
|
||||||
|
self.hostname = ""
|
||||||
|
|
||||||
# Load conf from ConfigDb
|
# Load conf from ConfigDb
|
||||||
def load(self, aaa_conf, tac_global_conf, tacplus_conf):
|
def load(self, aaa_conf, tac_global_conf, tacplus_conf, rad_global_conf, radius_conf):
|
||||||
for row in aaa_conf:
|
for row in aaa_conf:
|
||||||
self.aaa_update(row, aaa_conf[row], modify_conf=False)
|
self.aaa_update(row, aaa_conf[row], modify_conf=False)
|
||||||
for row in tac_global_conf:
|
for row in tac_global_conf:
|
||||||
self.tacacs_global_update(row, tac_global_conf[row], modify_conf=False)
|
self.tacacs_global_update(row, tac_global_conf[row], modify_conf=False)
|
||||||
for row in tacplus_conf:
|
for row in tacplus_conf:
|
||||||
self.tacacs_server_update(row, tacplus_conf[row], modify_conf=False)
|
self.tacacs_server_update(row, tacplus_conf[row], modify_conf=False)
|
||||||
|
|
||||||
|
for row in rad_global_conf:
|
||||||
|
self.radius_global_update(row, rad_global_conf[row], modify_conf=False)
|
||||||
|
for row in radius_conf:
|
||||||
|
self.radius_server_update(row, radius_conf[row], modify_conf=False)
|
||||||
|
|
||||||
self.modify_conf_file()
|
self.modify_conf_file()
|
||||||
|
|
||||||
def aaa_update(self, key, data, modify_conf=True):
|
def aaa_update(self, key, data, modify_conf=True):
|
||||||
@ -169,6 +200,29 @@ class AaaCfg(object):
|
|||||||
if modify_conf:
|
if modify_conf:
|
||||||
self.modify_conf_file()
|
self.modify_conf_file()
|
||||||
|
|
||||||
|
def pick_src_intf_ipaddrs(self, keys, src_intf):
|
||||||
|
new_ipv4_addr = ""
|
||||||
|
new_ipv6_addr = ""
|
||||||
|
|
||||||
|
for it in keys:
|
||||||
|
if src_intf != it[0] or (isinstance(it, tuple) == False):
|
||||||
|
continue
|
||||||
|
if new_ipv4_addr != "" and new_ipv6_addr != "":
|
||||||
|
break
|
||||||
|
ip_str = it[1].split("/")[0]
|
||||||
|
ip_addr = ipaddress.IPAddress(ip_str)
|
||||||
|
# Pick the first IP address from the table that matches the source interface
|
||||||
|
if isinstance(ip_addr, ipaddress.IPv6Address):
|
||||||
|
if new_ipv6_addr != "":
|
||||||
|
continue
|
||||||
|
new_ipv6_addr = ip_str
|
||||||
|
else:
|
||||||
|
if new_ipv4_addr != "":
|
||||||
|
continue
|
||||||
|
new_ipv4_addr = ip_str
|
||||||
|
|
||||||
|
return(new_ipv4_addr, new_ipv6_addr)
|
||||||
|
|
||||||
def tacacs_global_update(self, key, data, modify_conf=True):
|
def tacacs_global_update(self, key, data, modify_conf=True):
|
||||||
if key == 'global':
|
if key == 'global':
|
||||||
self.tacplus_global = data
|
self.tacplus_global = data
|
||||||
@ -185,6 +239,106 @@ class AaaCfg(object):
|
|||||||
if modify_conf:
|
if modify_conf:
|
||||||
self.modify_conf_file()
|
self.modify_conf_file()
|
||||||
|
|
||||||
|
def handle_radius_source_intf_ip_chg(self, key):
|
||||||
|
modify_conf=False
|
||||||
|
if 'src_intf' in self.radius_global:
|
||||||
|
if key[0] == self.radius_global['src_intf']:
|
||||||
|
modify_conf=True
|
||||||
|
for addr in self.radius_servers:
|
||||||
|
if ('src_intf' in self.radius_servers[addr]) and \
|
||||||
|
(key[0] == self.radius_servers[addr]['src_intf']):
|
||||||
|
modify_conf=True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not modify_conf:
|
||||||
|
return
|
||||||
|
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'RADIUS IP change - key:{}, current server info {}'.format(key, self.radius_servers))
|
||||||
|
self.modify_conf_file()
|
||||||
|
|
||||||
|
def handle_radius_nas_ip_chg(self, key):
|
||||||
|
modify_conf=False
|
||||||
|
# Mgmt IP configuration affects only the default nas_ip
|
||||||
|
if 'nas_ip' not in self.radius_global:
|
||||||
|
for addr in self.radius_servers:
|
||||||
|
if 'nas_ip' not in self.radius_servers[addr]:
|
||||||
|
modify_conf=True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not modify_conf:
|
||||||
|
return
|
||||||
|
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'RADIUS (NAS) IP change - key:{}, current global info {}'.format(key, self.radius_global))
|
||||||
|
self.modify_conf_file()
|
||||||
|
|
||||||
|
def radius_global_update(self, key, data, modify_conf=True):
|
||||||
|
if key == 'global':
|
||||||
|
self.radius_global = data
|
||||||
|
if 'statistics' in data:
|
||||||
|
self.radius_global['statistics'] = is_true(data['statistics'])
|
||||||
|
if modify_conf:
|
||||||
|
self.modify_conf_file()
|
||||||
|
|
||||||
|
def radius_server_update(self, key, data, modify_conf=True):
|
||||||
|
if data == {}:
|
||||||
|
if key in self.radius_servers:
|
||||||
|
del self.radius_servers[key]
|
||||||
|
else:
|
||||||
|
self.radius_servers[key] = data
|
||||||
|
|
||||||
|
if modify_conf:
|
||||||
|
self.modify_conf_file()
|
||||||
|
|
||||||
|
def hostname_update(self, hostname, modify_conf=True):
|
||||||
|
if self.hostname == hostname:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.hostname = hostname
|
||||||
|
|
||||||
|
# Currently only used for RADIUS
|
||||||
|
if len(self.radius_servers) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
if modify_conf:
|
||||||
|
self.modify_conf_file()
|
||||||
|
|
||||||
|
def get_hostname(self):
|
||||||
|
return self.hostname
|
||||||
|
|
||||||
|
def get_interface_ip(self, source, addr=None):
|
||||||
|
keys = None
|
||||||
|
try:
|
||||||
|
if source.startswith("Eth"):
|
||||||
|
if is_vlan_sub_interface(source):
|
||||||
|
keys = self.config_db.get_keys('VLAN_SUB_INTERFACE')
|
||||||
|
else:
|
||||||
|
keys = self.config_db.get_keys('INTERFACE')
|
||||||
|
elif source.startswith("Po"):
|
||||||
|
if is_vlan_sub_interface(source):
|
||||||
|
keys = self.config_db.get_keys('VLAN_SUB_INTERFACE')
|
||||||
|
else:
|
||||||
|
keys = self.config_db.get_keys('PORTCHANNEL_INTERFACE')
|
||||||
|
elif source.startswith("Vlan"):
|
||||||
|
keys = self.config_db.get_keys('VLAN_INTERFACE')
|
||||||
|
elif source.startswith("Loopback"):
|
||||||
|
keys = self.config_db.get_keys('LOOPBACK_INTERFACE')
|
||||||
|
elif source == "eth0":
|
||||||
|
keys = self.config_db.get_keys('MGMT_INTERFACE')
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
|
||||||
|
interface_ip = ""
|
||||||
|
if keys != None:
|
||||||
|
ipv4_addr, ipv6_addr = self.pick_src_intf_ipaddrs(keys, source)
|
||||||
|
# Based on the type of addr, return v4 or v6
|
||||||
|
if addr and isinstance(addr, ipaddress.IPv6Address):
|
||||||
|
interface_ip = ipv6_addr
|
||||||
|
else:
|
||||||
|
# This could be tuned, but that involves a DNS query, so
|
||||||
|
# offline configuration might trip (or cause delays).
|
||||||
|
interface_ip = ipv4_addr
|
||||||
|
return interface_ip
|
||||||
|
|
||||||
def modify_single_file(self, filename, operations=None):
|
def modify_single_file(self, filename, operations=None):
|
||||||
if operations:
|
if operations:
|
||||||
cmd = "sed -e {0} {1} > {1}.new; mv -f {1} {1}.old; mv -f {1}.new {1}".format(' -e '.join(operations), filename)
|
cmd = "sed -e {0} {1} > {1}.new; mv -f {1} {1}.old; mv -f {1}.new {1}".format(' -e '.join(operations), filename)
|
||||||
@ -209,29 +363,82 @@ class AaaCfg(object):
|
|||||||
servers_conf.append(server)
|
servers_conf.append(server)
|
||||||
servers_conf = sorted(servers_conf, key=lambda t: int(t['priority']), reverse=True)
|
servers_conf = sorted(servers_conf, key=lambda t: int(t['priority']), reverse=True)
|
||||||
|
|
||||||
|
radius_global = self.radius_global_default.copy()
|
||||||
|
radius_global.update(self.radius_global)
|
||||||
|
|
||||||
|
# RADIUS: Set the default nas_ip, and nas_id
|
||||||
|
if 'nas_ip' not in radius_global:
|
||||||
|
nas_ip = self.get_interface_ip("eth0")
|
||||||
|
if len(nas_ip) > 0:
|
||||||
|
radius_global['nas_ip'] = nas_ip
|
||||||
|
if 'nas_id' not in radius_global:
|
||||||
|
nas_id = self.get_hostname()
|
||||||
|
if len(nas_id) > 0:
|
||||||
|
radius_global['nas_id'] = nas_id
|
||||||
|
|
||||||
|
radsrvs_conf = []
|
||||||
|
if self.radius_servers:
|
||||||
|
for addr in self.radius_servers:
|
||||||
|
server = radius_global.copy()
|
||||||
|
server['ip'] = addr
|
||||||
|
server.update(self.radius_servers[addr])
|
||||||
|
|
||||||
|
if 'src_intf' in server:
|
||||||
|
# RADIUS: Log a message if src_ip is already defined.
|
||||||
|
if 'src_ip' in server:
|
||||||
|
syslog.syslog(syslog.LOG_INFO, \
|
||||||
|
"RADIUS_SERVER|{}: src_intf found. Ignoring src_ip".format(addr))
|
||||||
|
# RADIUS: If server.src_intf, then get the corresponding
|
||||||
|
# src_ip based on the server.ip, and set it.
|
||||||
|
src_ip = self.get_interface_ip(server['src_intf'], addr)
|
||||||
|
if len(src_ip) > 0:
|
||||||
|
server['src_ip'] = src_ip
|
||||||
|
elif 'src_ip' in server:
|
||||||
|
syslog.syslog(syslog.LOG_INFO, \
|
||||||
|
"RADIUS_SERVER|{}: src_intf has no usable IP addr.".format(addr))
|
||||||
|
del server['src_ip']
|
||||||
|
|
||||||
|
radsrvs_conf.append(server)
|
||||||
|
radsrvs_conf = sorted(radsrvs_conf, key=lambda t: int(t['priority']), reverse=True)
|
||||||
|
|
||||||
template_file = os.path.abspath(PAM_AUTH_CONF_TEMPLATE)
|
template_file = os.path.abspath(PAM_AUTH_CONF_TEMPLATE)
|
||||||
env = jinja2.Environment(loader=jinja2.FileSystemLoader('/'), trim_blocks=True)
|
env = jinja2.Environment(loader=jinja2.FileSystemLoader('/'), trim_blocks=True)
|
||||||
env.filters['sub'] = sub
|
env.filters['sub'] = sub
|
||||||
template = env.get_template(template_file)
|
template = env.get_template(template_file)
|
||||||
pam_conf = template.render(auth=auth, src_ip=src_ip, servers=servers_conf)
|
if 'radius' in auth['login']:
|
||||||
with open(PAM_AUTH_CONF, 'w') as f:
|
pam_conf = template.render(debug=self.debug, trace=self.trace, auth=auth, servers=radsrvs_conf)
|
||||||
f.write(pam_conf)
|
|
||||||
|
|
||||||
# Modify common-auth include file in /etc/pam.d/login and sshd
|
|
||||||
if os.path.isfile(PAM_AUTH_CONF):
|
|
||||||
self.modify_single_file('/etc/pam.d/sshd', [ "'/^@include/s/common-auth$/common-auth-sonic/'" ])
|
|
||||||
self.modify_single_file('/etc/pam.d/login', [ "'/^@include/s/common-auth$/common-auth-sonic/'" ])
|
|
||||||
else:
|
else:
|
||||||
self.modify_single_file('/etc/pam.d/sshd', [ "'/^@include/s/common-auth-sonic$/common-auth/'" ])
|
pam_conf = template.render(auth=auth, src_ip=src_ip, servers=servers_conf)
|
||||||
self.modify_single_file('/etc/pam.d/login', [ "'/^@include/s/common-auth-sonic$/common-auth/'" ])
|
|
||||||
|
|
||||||
# Add tacplus in nsswitch.conf if TACACS+ enable
|
# Use rename(), which is atomic (on the same fs) to avoid empty file
|
||||||
|
with open(PAM_AUTH_CONF + ".tmp", 'w') as f:
|
||||||
|
f.write(pam_conf)
|
||||||
|
os.chmod(PAM_AUTH_CONF + ".tmp", 0o644)
|
||||||
|
os.rename(PAM_AUTH_CONF + ".tmp", PAM_AUTH_CONF)
|
||||||
|
|
||||||
|
# Modify common-auth include file in /etc/pam.d/login, sshd.
|
||||||
|
# /etc/pam.d/sudo is not handled, because it would change the existing
|
||||||
|
# behavior. It can be modified once a config knob is added for sudo.
|
||||||
|
if os.path.isfile(PAM_AUTH_CONF):
|
||||||
|
self.modify_single_file(ETC_PAMD_SSHD, [ "'/^@include/s/common-auth$/common-auth-sonic/'" ])
|
||||||
|
self.modify_single_file(ETC_PAMD_LOGIN, [ "'/^@include/s/common-auth$/common-auth-sonic/'" ])
|
||||||
|
else:
|
||||||
|
self.modify_single_file(ETC_PAMD_SSHD, [ "'/^@include/s/common-auth-sonic$/common-auth/'" ])
|
||||||
|
self.modify_single_file(ETC_PAMD_LOGIN, [ "'/^@include/s/common-auth-sonic$/common-auth/'" ])
|
||||||
|
|
||||||
|
# Add tacplus/radius in nsswitch.conf if TACACS+/RADIUS enable
|
||||||
if 'tacacs+' in auth['login']:
|
if 'tacacs+' in auth['login']:
|
||||||
if os.path.isfile(NSS_CONF):
|
if os.path.isfile(NSS_CONF):
|
||||||
|
self.modify_single_file(NSS_CONF, [ "'/^passwd/s/ radius//'" ])
|
||||||
self.modify_single_file(NSS_CONF, [ "'/tacplus/b'", "'/^passwd/s/compat/tacplus &/'", "'/^passwd/s/files/tacplus &/'" ])
|
self.modify_single_file(NSS_CONF, [ "'/tacplus/b'", "'/^passwd/s/compat/tacplus &/'", "'/^passwd/s/files/tacplus &/'" ])
|
||||||
|
elif 'radius' in auth['login']:
|
||||||
|
if os.path.isfile(NSS_CONF):
|
||||||
|
self.modify_single_file(NSS_CONF, [ "'/^passwd/s/tacplus //'" ])
|
||||||
|
self.modify_single_file(NSS_CONF, [ "'/radius/b'", "'/^passwd/s/compat/& radius/'", "'/^passwd/s/files/& radius/'" ])
|
||||||
else:
|
else:
|
||||||
if os.path.isfile(NSS_CONF):
|
if os.path.isfile(NSS_CONF):
|
||||||
self.modify_single_file(NSS_CONF, [ "'/^passwd/s/tacplus //g'" ])
|
self.modify_single_file(NSS_CONF, [ "'/^passwd/s/tacplus //g'" ])
|
||||||
|
self.modify_single_file(NSS_CONF, [ "'/^passwd/s/ radius//'" ])
|
||||||
|
|
||||||
# Set tacacs+ server in nss-tacplus conf
|
# Set tacacs+ server in nss-tacplus conf
|
||||||
template_file = os.path.abspath(NSS_TACPLUS_CONF_TEMPLATE)
|
template_file = os.path.abspath(NSS_TACPLUS_CONF_TEMPLATE)
|
||||||
@ -240,6 +447,41 @@ class AaaCfg(object):
|
|||||||
with open(NSS_TACPLUS_CONF, 'w') as f:
|
with open(NSS_TACPLUS_CONF, 'w') as f:
|
||||||
f.write(nss_tacplus_conf)
|
f.write(nss_tacplus_conf)
|
||||||
|
|
||||||
|
# Set debug in nss-radius conf
|
||||||
|
template_file = os.path.abspath(NSS_RADIUS_CONF_TEMPLATE)
|
||||||
|
template = env.get_template(template_file)
|
||||||
|
nss_radius_conf = template.render(debug=self.debug, trace=self.trace, servers=radsrvs_conf)
|
||||||
|
with open(NSS_RADIUS_CONF, 'w') as f:
|
||||||
|
f.write(nss_radius_conf)
|
||||||
|
|
||||||
|
# Create the per server pam_radius_auth.conf
|
||||||
|
if radsrvs_conf:
|
||||||
|
for srv in radsrvs_conf:
|
||||||
|
# Configuration File
|
||||||
|
pam_radius_auth_file = RADIUS_PAM_AUTH_CONF_DIR + srv['ip'] + ":" + srv['auth_port'] + ".conf"
|
||||||
|
template_file = os.path.abspath(PAM_RADIUS_AUTH_CONF_TEMPLATE)
|
||||||
|
template = env.get_template(template_file)
|
||||||
|
pam_radius_auth_conf = template.render(server=srv)
|
||||||
|
|
||||||
|
open(pam_radius_auth_file, 'a').close()
|
||||||
|
os.chmod(pam_radius_auth_file, 0o600)
|
||||||
|
with open(pam_radius_auth_file, 'w+') as f:
|
||||||
|
f.write(pam_radius_auth_conf)
|
||||||
|
|
||||||
|
# Start the statistics service. Only RADIUS implemented
|
||||||
|
if ('radius' in auth['login']) and ('statistics' in radius_global) and\
|
||||||
|
radius_global['statistics']:
|
||||||
|
cmd = 'service aaastatsd start'
|
||||||
|
else:
|
||||||
|
cmd = 'service aaastatsd stop'
|
||||||
|
syslog.syslog(syslog.LOG_INFO, "cmd - {}".format(cmd))
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd, shell=True)
|
||||||
|
except subprocess.CalledProcessError as err:
|
||||||
|
syslog.syslog(syslog.LOG_ERR,
|
||||||
|
"{} - failed: return code - {}, output:\n{}"
|
||||||
|
.format(err.cmd, err.returncode, err.output))
|
||||||
|
|
||||||
class KdumpCfg(object):
|
class KdumpCfg(object):
|
||||||
def __init__(self, CfgDb):
|
def __init__(self, CfgDb):
|
||||||
self.config_db = CfgDb
|
self.config_db = CfgDb
|
||||||
@ -398,6 +640,7 @@ class HostConfigDaemon:
|
|||||||
self.device_config = {}
|
self.device_config = {}
|
||||||
self.device_config['DEVICE_METADATA'] = self.config_db.get_table('DEVICE_METADATA')
|
self.device_config['DEVICE_METADATA'] = self.config_db.get_table('DEVICE_METADATA')
|
||||||
|
|
||||||
|
self.hostname_cache=""
|
||||||
self.aaacfg = AaaCfg()
|
self.aaacfg = AaaCfg()
|
||||||
self.iptables = Iptables()
|
self.iptables = Iptables()
|
||||||
self.ntpcfg = NtpCfg(self.config_db)
|
self.ntpcfg = NtpCfg(self.config_db)
|
||||||
@ -415,7 +658,9 @@ class HostConfigDaemon:
|
|||||||
aaa = self.config_db.get_table('AAA')
|
aaa = self.config_db.get_table('AAA')
|
||||||
tacacs_global = self.config_db.get_table('TACPLUS')
|
tacacs_global = self.config_db.get_table('TACPLUS')
|
||||||
tacacs_server = self.config_db.get_table('TACPLUS_SERVER')
|
tacacs_server = self.config_db.get_table('TACPLUS_SERVER')
|
||||||
self.aaacfg.load(aaa, tacacs_global, tacacs_server)
|
radius_global = self.config_db.get_table('RADIUS')
|
||||||
|
radius_server = self.config_db.get_table('RADIUS_SERVER')
|
||||||
|
self.aaacfg.load(aaa, tacacs_global, tacacs_server, radius_global, radius_server)
|
||||||
|
|
||||||
lpbk_table = self.config_db.get_table('LOOPBACK_INTERFACE')
|
lpbk_table = self.config_db.get_table('LOOPBACK_INTERFACE')
|
||||||
self.iptables.load(lpbk_table)
|
self.iptables.load(lpbk_table)
|
||||||
@ -425,6 +670,16 @@ class HostConfigDaemon:
|
|||||||
ntp_global = self.config_db.get_table('NTP')
|
ntp_global = self.config_db.get_table('NTP')
|
||||||
self.ntpcfg.load(ntp_global, ntp_server)
|
self.ntpcfg.load(ntp_global, ntp_server)
|
||||||
|
|
||||||
|
try:
|
||||||
|
dev_meta = self.config_db.get_table('DEVICE_METADATA')
|
||||||
|
if 'localhost' in dev_meta:
|
||||||
|
if 'hostname' in dev_meta['localhost']:
|
||||||
|
self.hostname_cache = dev_meta['localhost']['hostname']
|
||||||
|
except Exception as e:
|
||||||
|
pass
|
||||||
|
# Update AAA with the hostname
|
||||||
|
self.aaacfg.hostname_update(self.hostname_cache)
|
||||||
|
|
||||||
def get_target_state(self, feature_name, state):
|
def get_target_state(self, feature_name, state):
|
||||||
template = jinja2.Template(state)
|
template = jinja2.Template(state)
|
||||||
target_state = template.render(self.device_config)
|
target_state = template.render(self.device_config)
|
||||||
@ -561,6 +816,24 @@ class HostConfigDaemon:
|
|||||||
log_data['passkey'] = obfuscate(log_data['passkey'])
|
log_data['passkey'] = obfuscate(log_data['passkey'])
|
||||||
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, log_data))
|
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, log_data))
|
||||||
|
|
||||||
|
def radius_server_handler(self, key, data):
|
||||||
|
self.aaacfg.radius_server_update(key, data)
|
||||||
|
log_data = copy.deepcopy(data)
|
||||||
|
if 'passkey' in log_data:
|
||||||
|
log_data['passkey'] = obfuscate(log_data['passkey'])
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, log_data))
|
||||||
|
|
||||||
|
def radius_global_handler(self, key, data):
|
||||||
|
self.aaacfg.radius_global_update(key, data)
|
||||||
|
log_data = copy.deepcopy(data)
|
||||||
|
if 'passkey' in log_data:
|
||||||
|
log_data['passkey'] = obfuscate(log_data['passkey'])
|
||||||
|
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, log_data))
|
||||||
|
|
||||||
|
def mgmt_intf_handler(self, key, data):
|
||||||
|
self.aaacfg.handle_radius_source_intf_ip_chg(key)
|
||||||
|
self.aaacfg.handle_radius_nas_ip_chg(key)
|
||||||
|
|
||||||
def lpbk_handler(self, key, data):
|
def lpbk_handler(self, key, data):
|
||||||
key = ConfigDBConnector.deserialize_key(key)
|
key = ConfigDBConnector.deserialize_key(key)
|
||||||
# Check if delete operation by fetch existing keys
|
# Check if delete operation by fetch existing keys
|
||||||
@ -572,6 +845,23 @@ class HostConfigDaemon:
|
|||||||
|
|
||||||
self.iptables.iptables_handler(key, data, add)
|
self.iptables.iptables_handler(key, data, add)
|
||||||
self.ntpcfg.handle_ntp_source_intf_chg(key)
|
self.ntpcfg.handle_ntp_source_intf_chg(key)
|
||||||
|
self.aaacfg.handle_radius_source_intf_ip_chg(key)
|
||||||
|
|
||||||
|
def vlan_intf_handler(self, key, data):
|
||||||
|
key = ConfigDBConnector.deserialize_key(key)
|
||||||
|
self.aaacfg.handle_radius_source_intf_ip_chg(key)
|
||||||
|
|
||||||
|
def vlan_sub_intf_handler(self, key, data):
|
||||||
|
key = ConfigDBConnector.deserialize_key(key)
|
||||||
|
self.aaacfg.handle_radius_source_intf_ip_chg(key)
|
||||||
|
|
||||||
|
def portchannel_intf_handler(self, key, data):
|
||||||
|
key = ConfigDBConnector.deserialize_key(key)
|
||||||
|
self.aaacfg.handle_radius_source_intf_ip_chg(key)
|
||||||
|
|
||||||
|
def phy_intf_handler(self, key, data):
|
||||||
|
key = ConfigDBConnector.deserialize_key(key)
|
||||||
|
self.aaacfg.handle_radius_source_intf_ip_chg(key)
|
||||||
|
|
||||||
def feature_state_handler(self, key, data):
|
def feature_state_handler(self, key, data):
|
||||||
feature_name = key
|
feature_name = key
|
||||||
@ -617,7 +907,14 @@ class HostConfigDaemon:
|
|||||||
self.config_db.subscribe('AAA', lambda table, key, data: self.aaa_handler(key, data))
|
self.config_db.subscribe('AAA', lambda table, key, data: self.aaa_handler(key, data))
|
||||||
self.config_db.subscribe('TACPLUS_SERVER', lambda table, key, data: self.tacacs_server_handler(key, data))
|
self.config_db.subscribe('TACPLUS_SERVER', lambda table, key, data: self.tacacs_server_handler(key, data))
|
||||||
self.config_db.subscribe('TACPLUS', lambda table, key, data: self.tacacs_global_handler(key, data))
|
self.config_db.subscribe('TACPLUS', lambda table, key, data: self.tacacs_global_handler(key, data))
|
||||||
|
self.config_db.subscribe('RADIUS_SERVER', lambda table, key, data: self.radius_server_handler(key, data))
|
||||||
|
self.config_db.subscribe('RADIUS', lambda table, key, data: self.radius_global_handler(key, data))
|
||||||
|
self.config_db.subscribe('MGMT_INTERFACE', lambda table, key, data: self.mgmt_intf_handler(key, data))
|
||||||
self.config_db.subscribe('LOOPBACK_INTERFACE', lambda table, key, data: self.lpbk_handler(key, data))
|
self.config_db.subscribe('LOOPBACK_INTERFACE', lambda table, key, data: self.lpbk_handler(key, data))
|
||||||
|
self.config_db.subscribe('VLAN_INTERFACE', lambda table, key, data: self.vlan_intf_handler(key, data))
|
||||||
|
self.config_db.subscribe('VLAN_SUB_INTERFACE', lambda table, key, data: self.vlan_sub_intf_handler(key, data))
|
||||||
|
self.config_db.subscribe('PORTCHANNEL_INTERFACE', lambda table, key, data: self.portchannel_intf_handler(key, data))
|
||||||
|
self.config_db.subscribe('INTERFACE', lambda table, key, data: self.phy_intf_handler(key, data))
|
||||||
self.config_db.subscribe('FEATURE', lambda table, key, data: self.feature_state_handler(key, data))
|
self.config_db.subscribe('FEATURE', lambda table, key, data: self.feature_state_handler(key, data))
|
||||||
self.config_db.subscribe('NTP_SERVER', lambda table, key, data: self.ntp_server_handler(key, data))
|
self.config_db.subscribe('NTP_SERVER', lambda table, key, data: self.ntp_server_handler(key, data))
|
||||||
self.config_db.subscribe('NTP', lambda table, key, data: self.ntp_global_handler(key, data))
|
self.config_db.subscribe('NTP', lambda table, key, data: self.ntp_global_handler(key, data))
|
||||||
|
@ -16,6 +16,7 @@ setup(
|
|||||||
scripts = [
|
scripts = [
|
||||||
'scripts/caclmgrd',
|
'scripts/caclmgrd',
|
||||||
'scripts/hostcfgd',
|
'scripts/hostcfgd',
|
||||||
|
'scripts/aaastatsd',
|
||||||
'scripts/procdockerstatsd',
|
'scripts/procdockerstatsd',
|
||||||
'scripts/determine-reboot-cause',
|
'scripts/determine-reboot-cause',
|
||||||
'scripts/process-reboot-cause',
|
'scripts/process-reboot-cause',
|
||||||
|
102
src/sonic-host-services/tests/hostcfgd/hostcfgd_radius_test.py
Normal file
102
src/sonic-host-services/tests/hostcfgd/hostcfgd_radius_test.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import importlib.machinery
|
||||||
|
import importlib.util
|
||||||
|
import filecmp
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import subprocess
|
||||||
|
import swsssdk
|
||||||
|
|
||||||
|
from parameterized import parameterized
|
||||||
|
from unittest import TestCase, mock
|
||||||
|
from tests.hostcfgd.test_radius_vectors import HOSTCFGD_TEST_RADIUS_VECTOR
|
||||||
|
from tests.hostcfgd.mock_configdb import MockConfigDb
|
||||||
|
|
||||||
|
|
||||||
|
swsssdk.ConfigDBConnector = MockConfigDb
|
||||||
|
test_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
modules_path = os.path.dirname(test_path)
|
||||||
|
scripts_path = os.path.join(modules_path, "scripts")
|
||||||
|
src_path = os.path.dirname(modules_path)
|
||||||
|
templates_path = os.path.join(src_path, "sonic-host-services-data/templates")
|
||||||
|
output_path = os.path.join(test_path, "hostcfgd/output")
|
||||||
|
sample_output_path = os.path.join(test_path, "hostcfgd/sample_output")
|
||||||
|
sys.path.insert(0, modules_path)
|
||||||
|
|
||||||
|
# Load the file under test
|
||||||
|
hostcfgd_path = os.path.join(scripts_path, 'hostcfgd')
|
||||||
|
loader = importlib.machinery.SourceFileLoader('hostcfgd', hostcfgd_path)
|
||||||
|
spec = importlib.util.spec_from_loader(loader.name, loader)
|
||||||
|
hostcfgd = importlib.util.module_from_spec(spec)
|
||||||
|
loader.exec_module(hostcfgd)
|
||||||
|
sys.modules['hostcfgd'] = hostcfgd
|
||||||
|
|
||||||
|
|
||||||
|
class TestHostcfgdRADIUS(TestCase):
|
||||||
|
"""
|
||||||
|
Test hostcfd daemon - RADIUS
|
||||||
|
"""
|
||||||
|
def run_diff(self, file1, file2):
|
||||||
|
return subprocess.check_output('diff -uR {} {} || true'.format(file1, file2), shell=True)
|
||||||
|
|
||||||
|
|
||||||
|
@parameterized.expand(HOSTCFGD_TEST_RADIUS_VECTOR)
|
||||||
|
def test_hostcfgd_radius(self, test_name, test_data):
|
||||||
|
"""
|
||||||
|
Test RADIUS hostcfd daemon initialization
|
||||||
|
|
||||||
|
Args:
|
||||||
|
test_name(str): test name
|
||||||
|
test_data(dict): test data which contains initial Config Db tables, and expected results
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
None
|
||||||
|
"""
|
||||||
|
|
||||||
|
t_path = templates_path
|
||||||
|
op_path = output_path + "/" + test_name
|
||||||
|
sop_path = sample_output_path + "/" + test_name
|
||||||
|
|
||||||
|
hostcfgd.PAM_AUTH_CONF_TEMPLATE = t_path + "/common-auth-sonic.j2"
|
||||||
|
hostcfgd.NSS_TACPLUS_CONF_TEMPLATE = t_path + "/tacplus_nss.conf.j2"
|
||||||
|
hostcfgd.NSS_RADIUS_CONF_TEMPLATE = t_path + "/radius_nss.conf.j2"
|
||||||
|
hostcfgd.PAM_RADIUS_AUTH_CONF_TEMPLATE = t_path + "/pam_radius_auth.conf.j2"
|
||||||
|
hostcfgd.PAM_AUTH_CONF = op_path + "/common-auth-sonic"
|
||||||
|
hostcfgd.NSS_TACPLUS_CONF = op_path + "/tacplus_nss.conf"
|
||||||
|
hostcfgd.NSS_RADIUS_CONF = op_path + "/radius_nss.conf"
|
||||||
|
hostcfgd.NSS_CONF = op_path + "/nsswitch.conf"
|
||||||
|
hostcfgd.ETC_PAMD_SSHD = op_path + "/sshd"
|
||||||
|
hostcfgd.ETC_PAMD_LOGIN = op_path + "/login"
|
||||||
|
hostcfgd.RADIUS_PAM_AUTH_CONF_DIR = op_path + "/"
|
||||||
|
|
||||||
|
shutil.rmtree( op_path, ignore_errors=True)
|
||||||
|
os.mkdir( op_path)
|
||||||
|
|
||||||
|
shutil.copyfile( sop_path + "/sshd.old", op_path + "/sshd")
|
||||||
|
shutil.copyfile( sop_path + "/login.old", op_path + "/login")
|
||||||
|
|
||||||
|
MockConfigDb.set_config_db(test_data["config_db"])
|
||||||
|
host_config_daemon = hostcfgd.HostConfigDaemon()
|
||||||
|
|
||||||
|
aaa = host_config_daemon.config_db.get_table('AAA')
|
||||||
|
|
||||||
|
try:
|
||||||
|
radius_global = host_config_daemon.config_db.get_table('RADIUS')
|
||||||
|
except:
|
||||||
|
radius_global = []
|
||||||
|
try:
|
||||||
|
radius_server = \
|
||||||
|
host_config_daemon.config_db.get_table('RADIUS_SERVER')
|
||||||
|
except:
|
||||||
|
radius_server = []
|
||||||
|
|
||||||
|
host_config_daemon.aaacfg.load(aaa,[],[],radius_global,radius_server)
|
||||||
|
dcmp = filecmp.dircmp(sop_path, op_path)
|
||||||
|
diff_output = ""
|
||||||
|
for name in dcmp.diff_files:
|
||||||
|
diff_output += \
|
||||||
|
"Diff: file: {} expected: {} output: {}\n".format(\
|
||||||
|
name, dcmp.left, dcmp.right)
|
||||||
|
diff_output += self.run_diff( dcmp.left + "/" + name,\
|
||||||
|
dcmp.right + "/" + name)
|
||||||
|
self.assertTrue(len(diff_output) == 0, diff_output)
|
4
src/sonic-host-services/tests/hostcfgd/output/.gitignore
vendored
Normal file
4
src/sonic-host-services/tests/hostcfgd/output/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Ignore all test generated files
|
||||||
|
*
|
||||||
|
# But keep this file
|
||||||
|
!.gitignore
|
@ -0,0 +1,21 @@
|
|||||||
|
#THIS IS AN AUTO-GENERATED FILE
|
||||||
|
#
|
||||||
|
# /etc/pam.d/common-auth- authentication settings common to all services
|
||||||
|
# This file is included from other service-specific PAM config files,
|
||||||
|
# and should contain a list of the authentication modules that define
|
||||||
|
# the central authentication scheme for use on the system
|
||||||
|
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
|
||||||
|
# traditional Unix authentication mechanisms.
|
||||||
|
#
|
||||||
|
# here are the per-package modules (the "Primary" block)
|
||||||
|
|
||||||
|
auth [success=1 default=ignore] pam_unix.so nullok try_first_pass
|
||||||
|
|
||||||
|
#
|
||||||
|
# here's the fallback if no module succeeds
|
||||||
|
auth requisite pam_deny.so
|
||||||
|
# prime the stack with a positive return value if there isn't one already;
|
||||||
|
# this avoids us returning an error just because nothing sets a success code
|
||||||
|
# since the modules above will each just jump around
|
||||||
|
auth required pam_permit.so
|
||||||
|
# and here are more per-package modules (the "Additional" block)
|
116
src/sonic-host-services/tests/hostcfgd/sample_output/LOCAL/login
Normal file
116
src/sonic-host-services/tests/hostcfgd/sample_output/LOCAL/login
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#
|
||||||
|
# The PAM configuration file for the Shadow `login' service
|
||||||
|
#
|
||||||
|
|
||||||
|
# Enforce a minimal delay in case of failure (in microseconds).
|
||||||
|
# (Replaces the `FAIL_DELAY' setting from login.defs)
|
||||||
|
# Note that other modules may require another minimal delay. (for example,
|
||||||
|
# to disable any delay, you should add the nodelay option to pam_unix)
|
||||||
|
auth optional pam_faildelay.so delay=3000000
|
||||||
|
|
||||||
|
# Outputs an issue file prior to each login prompt (Replaces the
|
||||||
|
# ISSUE_FILE option from login.defs). Uncomment for use
|
||||||
|
# auth required pam_issue.so issue=/etc/issue
|
||||||
|
|
||||||
|
# Disallows root logins except on tty's listed in /etc/securetty
|
||||||
|
# (Replaces the `CONSOLE' setting from login.defs)
|
||||||
|
#
|
||||||
|
# With the default control of this module:
|
||||||
|
# [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die]
|
||||||
|
# root will not be prompted for a password on insecure lines.
|
||||||
|
# if an invalid username is entered, a password is prompted (but login
|
||||||
|
# will eventually be rejected)
|
||||||
|
#
|
||||||
|
# You can change it to a "requisite" module if you think root may mis-type
|
||||||
|
# her login and should not be prompted for a password in that case. But
|
||||||
|
# this will leave the system as vulnerable to user enumeration attacks.
|
||||||
|
#
|
||||||
|
# You can change it to a "required" module if you think it permits to
|
||||||
|
# guess valid user names of your system (invalid user names are considered
|
||||||
|
# as possibly being root on insecure lines), but root passwords may be
|
||||||
|
# communicated over insecure lines.
|
||||||
|
auth [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die] pam_securetty.so
|
||||||
|
|
||||||
|
# Disallows other than root logins when /etc/nologin exists
|
||||||
|
# (Replaces the `NOLOGINS_FILE' option from login.defs)
|
||||||
|
auth requisite pam_nologin.so
|
||||||
|
|
||||||
|
# SELinux needs to be the first session rule. This ensures that any
|
||||||
|
# lingering context has been cleared. Without this it is possible
|
||||||
|
# that a module could execute code in the wrong domain.
|
||||||
|
# When the module is present, "required" would be sufficient (When SELinux
|
||||||
|
# is disabled, this returns success.)
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
|
||||||
|
|
||||||
|
# Sets the loginuid process attribute
|
||||||
|
session required pam_loginuid.so
|
||||||
|
|
||||||
|
# SELinux needs to intervene at login time to ensure that the process
|
||||||
|
# starts in the proper default security context. Only sessions which are
|
||||||
|
# intended to run in the user's context should be run after this.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
|
||||||
|
# When the module is present, "required" would be sufficient (When SELinux
|
||||||
|
# is disabled, this returns success.)
|
||||||
|
|
||||||
|
# This module parses environment configuration file(s)
|
||||||
|
# and also allows you to use an extended config
|
||||||
|
# file /etc/security/pam_env.conf.
|
||||||
|
#
|
||||||
|
# parsing /etc/environment needs "readenv=1"
|
||||||
|
session required pam_env.so readenv=1
|
||||||
|
# locale variables are also kept into /etc/default/locale in etch
|
||||||
|
# reading this file *in addition to /etc/environment* does not hurt
|
||||||
|
session required pam_env.so readenv=1 envfile=/etc/default/locale
|
||||||
|
|
||||||
|
# Standard Un*x authentication.
|
||||||
|
@include common-auth-sonic
|
||||||
|
|
||||||
|
# This allows certain extra groups to be granted to a user
|
||||||
|
# based on things like time of day, tty, service, and user.
|
||||||
|
# Please edit /etc/security/group.conf to fit your needs
|
||||||
|
# (Replaces the `CONSOLE_GROUPS' option in login.defs)
|
||||||
|
auth optional pam_group.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/time.conf if you need to set
|
||||||
|
# time restraint on logins.
|
||||||
|
# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs
|
||||||
|
# as well as /etc/porttime)
|
||||||
|
# account requisite pam_time.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/access.conf if you need to
|
||||||
|
# set access limits.
|
||||||
|
# (Replaces /etc/login.access file)
|
||||||
|
# account required pam_access.so
|
||||||
|
|
||||||
|
# Sets up user limits according to /etc/security/limits.conf
|
||||||
|
# (Replaces the use of /etc/limits in old login)
|
||||||
|
session required pam_limits.so
|
||||||
|
|
||||||
|
# Prints the last login info upon successful login
|
||||||
|
# (Replaces the `LASTLOG_ENAB' option from login.defs)
|
||||||
|
session optional pam_lastlog.so
|
||||||
|
|
||||||
|
# Prints the message of the day upon successful login.
|
||||||
|
# (Replaces the `MOTD_FILE' option in login.defs)
|
||||||
|
# This includes a dynamically generated part from /run/motd.dynamic
|
||||||
|
# and a static (admin-editable) part from /etc/motd.
|
||||||
|
session optional pam_motd.so motd=/run/motd.dynamic
|
||||||
|
session optional pam_motd.so noupdate
|
||||||
|
|
||||||
|
# Prints the status of the user's mailbox upon successful login
|
||||||
|
# (Replaces the `MAIL_CHECK_ENAB' option from login.defs).
|
||||||
|
#
|
||||||
|
# This also defines the MAIL environment variable
|
||||||
|
# However, userdel also needs MAIL_DIR and MAIL_FILE variables
|
||||||
|
# in /etc/login.defs to make sure that removing a user
|
||||||
|
# also removes the user's mail spool file.
|
||||||
|
# See comments in /etc/login.defs
|
||||||
|
session optional pam_mail.so standard
|
||||||
|
|
||||||
|
# Create a new session keyring.
|
||||||
|
session optional pam_keyinit.so force revoke
|
||||||
|
|
||||||
|
# Standard Un*x account and session
|
||||||
|
@include common-account
|
||||||
|
@include common-session
|
||||||
|
@include common-password
|
@ -0,0 +1,116 @@
|
|||||||
|
#
|
||||||
|
# The PAM configuration file for the Shadow `login' service
|
||||||
|
#
|
||||||
|
|
||||||
|
# Enforce a minimal delay in case of failure (in microseconds).
|
||||||
|
# (Replaces the `FAIL_DELAY' setting from login.defs)
|
||||||
|
# Note that other modules may require another minimal delay. (for example,
|
||||||
|
# to disable any delay, you should add the nodelay option to pam_unix)
|
||||||
|
auth optional pam_faildelay.so delay=3000000
|
||||||
|
|
||||||
|
# Outputs an issue file prior to each login prompt (Replaces the
|
||||||
|
# ISSUE_FILE option from login.defs). Uncomment for use
|
||||||
|
# auth required pam_issue.so issue=/etc/issue
|
||||||
|
|
||||||
|
# Disallows root logins except on tty's listed in /etc/securetty
|
||||||
|
# (Replaces the `CONSOLE' setting from login.defs)
|
||||||
|
#
|
||||||
|
# With the default control of this module:
|
||||||
|
# [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die]
|
||||||
|
# root will not be prompted for a password on insecure lines.
|
||||||
|
# if an invalid username is entered, a password is prompted (but login
|
||||||
|
# will eventually be rejected)
|
||||||
|
#
|
||||||
|
# You can change it to a "requisite" module if you think root may mis-type
|
||||||
|
# her login and should not be prompted for a password in that case. But
|
||||||
|
# this will leave the system as vulnerable to user enumeration attacks.
|
||||||
|
#
|
||||||
|
# You can change it to a "required" module if you think it permits to
|
||||||
|
# guess valid user names of your system (invalid user names are considered
|
||||||
|
# as possibly being root on insecure lines), but root passwords may be
|
||||||
|
# communicated over insecure lines.
|
||||||
|
auth [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die] pam_securetty.so
|
||||||
|
|
||||||
|
# Disallows other than root logins when /etc/nologin exists
|
||||||
|
# (Replaces the `NOLOGINS_FILE' option from login.defs)
|
||||||
|
auth requisite pam_nologin.so
|
||||||
|
|
||||||
|
# SELinux needs to be the first session rule. This ensures that any
|
||||||
|
# lingering context has been cleared. Without this it is possible
|
||||||
|
# that a module could execute code in the wrong domain.
|
||||||
|
# When the module is present, "required" would be sufficient (When SELinux
|
||||||
|
# is disabled, this returns success.)
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
|
||||||
|
|
||||||
|
# Sets the loginuid process attribute
|
||||||
|
session required pam_loginuid.so
|
||||||
|
|
||||||
|
# SELinux needs to intervene at login time to ensure that the process
|
||||||
|
# starts in the proper default security context. Only sessions which are
|
||||||
|
# intended to run in the user's context should be run after this.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
|
||||||
|
# When the module is present, "required" would be sufficient (When SELinux
|
||||||
|
# is disabled, this returns success.)
|
||||||
|
|
||||||
|
# This module parses environment configuration file(s)
|
||||||
|
# and also allows you to use an extended config
|
||||||
|
# file /etc/security/pam_env.conf.
|
||||||
|
#
|
||||||
|
# parsing /etc/environment needs "readenv=1"
|
||||||
|
session required pam_env.so readenv=1
|
||||||
|
# locale variables are also kept into /etc/default/locale in etch
|
||||||
|
# reading this file *in addition to /etc/environment* does not hurt
|
||||||
|
session required pam_env.so readenv=1 envfile=/etc/default/locale
|
||||||
|
|
||||||
|
# Standard Un*x authentication.
|
||||||
|
@include common-auth
|
||||||
|
|
||||||
|
# This allows certain extra groups to be granted to a user
|
||||||
|
# based on things like time of day, tty, service, and user.
|
||||||
|
# Please edit /etc/security/group.conf to fit your needs
|
||||||
|
# (Replaces the `CONSOLE_GROUPS' option in login.defs)
|
||||||
|
auth optional pam_group.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/time.conf if you need to set
|
||||||
|
# time restraint on logins.
|
||||||
|
# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs
|
||||||
|
# as well as /etc/porttime)
|
||||||
|
# account requisite pam_time.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/access.conf if you need to
|
||||||
|
# set access limits.
|
||||||
|
# (Replaces /etc/login.access file)
|
||||||
|
# account required pam_access.so
|
||||||
|
|
||||||
|
# Sets up user limits according to /etc/security/limits.conf
|
||||||
|
# (Replaces the use of /etc/limits in old login)
|
||||||
|
session required pam_limits.so
|
||||||
|
|
||||||
|
# Prints the last login info upon successful login
|
||||||
|
# (Replaces the `LASTLOG_ENAB' option from login.defs)
|
||||||
|
session optional pam_lastlog.so
|
||||||
|
|
||||||
|
# Prints the message of the day upon successful login.
|
||||||
|
# (Replaces the `MOTD_FILE' option in login.defs)
|
||||||
|
# This includes a dynamically generated part from /run/motd.dynamic
|
||||||
|
# and a static (admin-editable) part from /etc/motd.
|
||||||
|
session optional pam_motd.so motd=/run/motd.dynamic
|
||||||
|
session optional pam_motd.so noupdate
|
||||||
|
|
||||||
|
# Prints the status of the user's mailbox upon successful login
|
||||||
|
# (Replaces the `MAIL_CHECK_ENAB' option from login.defs).
|
||||||
|
#
|
||||||
|
# This also defines the MAIL environment variable
|
||||||
|
# However, userdel also needs MAIL_DIR and MAIL_FILE variables
|
||||||
|
# in /etc/login.defs to make sure that removing a user
|
||||||
|
# also removes the user's mail spool file.
|
||||||
|
# See comments in /etc/login.defs
|
||||||
|
session optional pam_mail.so standard
|
||||||
|
|
||||||
|
# Create a new session keyring.
|
||||||
|
session optional pam_keyinit.so force revoke
|
||||||
|
|
||||||
|
# Standard Un*x account and session
|
||||||
|
@include common-account
|
||||||
|
@include common-session
|
||||||
|
@include common-password
|
@ -0,0 +1,56 @@
|
|||||||
|
#THIS IS AN AUTO-GENERATED FILE
|
||||||
|
# Generated from: /usr/share/sonic/templates/radius_nss.conf.j2
|
||||||
|
# RADIUS NSS Configuration File
|
||||||
|
#
|
||||||
|
# Debug: on|off|trace
|
||||||
|
# Default: off
|
||||||
|
#
|
||||||
|
# debug=on
|
||||||
|
debug=on
|
||||||
|
|
||||||
|
#
|
||||||
|
# User Privilege:
|
||||||
|
# Default:
|
||||||
|
# user_priv=15;pw_info=remote_user_su;gid=1000;group=sudo,docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=1;pw_info=remote_user;gid=999;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# user_priv=15;pw_info=remote_user_su;gid=1000;group=sudo,docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=7;pw_info=netops;gid=999;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=1;pw_info=operator;gid=100;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
#
|
||||||
|
|
||||||
|
# many_to_one:
|
||||||
|
# y: Map RADIUS users to one local user per privilege.
|
||||||
|
# n: Create local user account on first successful authentication.
|
||||||
|
# Default: n
|
||||||
|
#
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# many_to_one=y
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_disallow:
|
||||||
|
# y: Do not allow unconfirmed users (users created before authentication)
|
||||||
|
# n: Allow unconfirmed users.
|
||||||
|
# Default: n
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# unconfirmed_disallow=y
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_ageout:
|
||||||
|
# <seconds>: Wait time before purging unconfirmed users
|
||||||
|
# Default: 600
|
||||||
|
#
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# unconfirmed_ageout=900
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_regexp:
|
||||||
|
# <regexp>: The RE to match the command line of processes for which the
|
||||||
|
# creation of unconfirmed users are to be allowed.
|
||||||
|
# Default: (.*: <user> \[priv\])|(.*: \[accepted\])
|
||||||
|
# where: <user> is the unconfirmed user.
|
||||||
|
#
|
@ -0,0 +1,55 @@
|
|||||||
|
# PAM configuration for the Secure Shell service
|
||||||
|
|
||||||
|
# Standard Un*x authentication.
|
||||||
|
@include common-auth-sonic
|
||||||
|
|
||||||
|
# Disallow non-root logins when /etc/nologin exists.
|
||||||
|
account required pam_nologin.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/access.conf if you need to set complex
|
||||||
|
# access limits that are hard to express in sshd_config.
|
||||||
|
# account required pam_access.so
|
||||||
|
|
||||||
|
# Standard Un*x authorization.
|
||||||
|
@include common-account
|
||||||
|
|
||||||
|
# SELinux needs to be the first session rule. This ensures that any
|
||||||
|
# lingering context has been cleared. Without this it is possible that a
|
||||||
|
# module could execute code in the wrong domain.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
|
||||||
|
|
||||||
|
# Set the loginuid process attribute.
|
||||||
|
session required pam_loginuid.so
|
||||||
|
|
||||||
|
# Create a new session keyring.
|
||||||
|
session optional pam_keyinit.so force revoke
|
||||||
|
|
||||||
|
# Standard Un*x session setup and teardown.
|
||||||
|
@include common-session
|
||||||
|
|
||||||
|
# Print the message of the day upon successful login.
|
||||||
|
# This includes a dynamically generated part from /run/motd.dynamic
|
||||||
|
# and a static (admin-editable) part from /etc/motd.
|
||||||
|
session optional pam_motd.so motd=/run/motd.dynamic
|
||||||
|
session optional pam_motd.so noupdate
|
||||||
|
|
||||||
|
# Print the status of the user's mailbox upon successful login.
|
||||||
|
session optional pam_mail.so standard noenv # [1]
|
||||||
|
|
||||||
|
# Set up user limits from /etc/security/limits.conf.
|
||||||
|
session required pam_limits.so
|
||||||
|
|
||||||
|
# Read environment variables from /etc/environment and
|
||||||
|
# /etc/security/pam_env.conf.
|
||||||
|
session required pam_env.so # [1]
|
||||||
|
# In Debian 4.0 (etch), locale-related environment variables were moved to
|
||||||
|
# /etc/default/locale, so read that as well.
|
||||||
|
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
|
||||||
|
|
||||||
|
# SELinux needs to intervene at login time to ensure that the process starts
|
||||||
|
# in the proper default security context. Only sessions which are intended
|
||||||
|
# to run in the user's context should be run after this.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
|
||||||
|
|
||||||
|
# Standard Un*x password updating.
|
||||||
|
@include common-password
|
@ -0,0 +1,55 @@
|
|||||||
|
# PAM configuration for the Secure Shell service
|
||||||
|
|
||||||
|
# Standard Un*x authentication.
|
||||||
|
@include common-auth
|
||||||
|
|
||||||
|
# Disallow non-root logins when /etc/nologin exists.
|
||||||
|
account required pam_nologin.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/access.conf if you need to set complex
|
||||||
|
# access limits that are hard to express in sshd_config.
|
||||||
|
# account required pam_access.so
|
||||||
|
|
||||||
|
# Standard Un*x authorization.
|
||||||
|
@include common-account
|
||||||
|
|
||||||
|
# SELinux needs to be the first session rule. This ensures that any
|
||||||
|
# lingering context has been cleared. Without this it is possible that a
|
||||||
|
# module could execute code in the wrong domain.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
|
||||||
|
|
||||||
|
# Set the loginuid process attribute.
|
||||||
|
session required pam_loginuid.so
|
||||||
|
|
||||||
|
# Create a new session keyring.
|
||||||
|
session optional pam_keyinit.so force revoke
|
||||||
|
|
||||||
|
# Standard Un*x session setup and teardown.
|
||||||
|
@include common-session
|
||||||
|
|
||||||
|
# Print the message of the day upon successful login.
|
||||||
|
# This includes a dynamically generated part from /run/motd.dynamic
|
||||||
|
# and a static (admin-editable) part from /etc/motd.
|
||||||
|
session optional pam_motd.so motd=/run/motd.dynamic
|
||||||
|
session optional pam_motd.so noupdate
|
||||||
|
|
||||||
|
# Print the status of the user's mailbox upon successful login.
|
||||||
|
session optional pam_mail.so standard noenv # [1]
|
||||||
|
|
||||||
|
# Set up user limits from /etc/security/limits.conf.
|
||||||
|
session required pam_limits.so
|
||||||
|
|
||||||
|
# Read environment variables from /etc/environment and
|
||||||
|
# /etc/security/pam_env.conf.
|
||||||
|
session required pam_env.so # [1]
|
||||||
|
# In Debian 4.0 (etch), locale-related environment variables were moved to
|
||||||
|
# /etc/default/locale, so read that as well.
|
||||||
|
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
|
||||||
|
|
||||||
|
# SELinux needs to intervene at login time to ensure that the process starts
|
||||||
|
# in the proper default security context. Only sessions which are intended
|
||||||
|
# to run in the user's context should be run after this.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
|
||||||
|
|
||||||
|
# Standard Un*x password updating.
|
||||||
|
@include common-password
|
@ -0,0 +1,23 @@
|
|||||||
|
# Configuration for libnss-tacplus
|
||||||
|
|
||||||
|
# debug - If you want to open debug log, set it on
|
||||||
|
# Default: off
|
||||||
|
# debug=on
|
||||||
|
debug=on
|
||||||
|
|
||||||
|
# src_ip - set source address of TACACS+ protocol packets
|
||||||
|
# Default: None (auto source ip address)
|
||||||
|
# src_ip=2.2.2.2
|
||||||
|
|
||||||
|
# server - set ip address, tcp port, secret string and timeout for TACACS+ servers
|
||||||
|
# Default: None (no TACACS+ server)
|
||||||
|
# server=1.1.1.1:49,secret=test,timeout=3
|
||||||
|
|
||||||
|
# user_priv - set the map between TACACS+ user privilege and local user's passwd
|
||||||
|
# Default:
|
||||||
|
# user_priv=15;pw_info=remote_user_su;gid=1000;group=sudo,docker;shell=/bin/bash
|
||||||
|
# user_priv=1;pw_info=remote_user;gid=999;group=docker;shell=/bin/bash
|
||||||
|
|
||||||
|
# many_to_one - create one local user for many TACACS+ users which has the same privilege
|
||||||
|
# Default: many_to_one=n
|
||||||
|
# many_to_one=y
|
@ -0,0 +1,2 @@
|
|||||||
|
# server[:port] shared_secret timeout(s) source_ip vrf
|
||||||
|
[10.10.10.1]:1645 pass1 1
|
@ -0,0 +1,2 @@
|
|||||||
|
# server[:port] shared_secret timeout(s) source_ip vrf
|
||||||
|
[10.10.10.2]:1645 pass2 2
|
@ -0,0 +1,30 @@
|
|||||||
|
#THIS IS AN AUTO-GENERATED FILE
|
||||||
|
#
|
||||||
|
# /etc/pam.d/common-auth- authentication settings common to all services
|
||||||
|
# This file is included from other service-specific PAM config files,
|
||||||
|
# and should contain a list of the authentication modules that define
|
||||||
|
# the central authentication scheme for use on the system
|
||||||
|
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
|
||||||
|
# traditional Unix authentication mechanisms.
|
||||||
|
#
|
||||||
|
# here are the per-package modules (the "Primary" block)
|
||||||
|
|
||||||
|
# root user can only be authenticated locally. Jump to local.
|
||||||
|
auth [success=2 default=ignore] pam_succeed_if.so user = root
|
||||||
|
# For the RADIUS servers, on success jump to the cache the MPL(Privilege)
|
||||||
|
auth [success=3 new_authtok_reqd=done default=ignore auth_err=die] pam_radius_auth.so conf=/etc/pam_radius_auth.d/10.10.10.1:1645.conf privilege_level protocol=pap retry=1 nas_ip_address=10.10.10.10 debug try_first_pass
|
||||||
|
auth [success=2 new_authtok_reqd=done default=ignore auth_err=die] pam_radius_auth.so conf=/etc/pam_radius_auth.d/10.10.10.2:1645.conf privilege_level protocol=chap retry=2 nas_ip_address=10.10.10.10 debug try_first_pass
|
||||||
|
# Local
|
||||||
|
auth [success=done new_authtok_reqd=done default=ignore auth_err=die maxtries=die] pam_unix.so nullok try_first_pass
|
||||||
|
auth requisite pam_deny.so
|
||||||
|
# Cache MPL(Privilege)
|
||||||
|
auth [success=1 default=ignore] pam_exec.so /usr/sbin/cache_radius
|
||||||
|
|
||||||
|
#
|
||||||
|
# here's the fallback if no module succeeds
|
||||||
|
auth requisite pam_deny.so
|
||||||
|
# prime the stack with a positive return value if there isn't one already;
|
||||||
|
# this avoids us returning an error just because nothing sets a success code
|
||||||
|
# since the modules above will each just jump around
|
||||||
|
auth required pam_permit.so
|
||||||
|
# and here are more per-package modules (the "Additional" block)
|
@ -0,0 +1,116 @@
|
|||||||
|
#
|
||||||
|
# The PAM configuration file for the Shadow `login' service
|
||||||
|
#
|
||||||
|
|
||||||
|
# Enforce a minimal delay in case of failure (in microseconds).
|
||||||
|
# (Replaces the `FAIL_DELAY' setting from login.defs)
|
||||||
|
# Note that other modules may require another minimal delay. (for example,
|
||||||
|
# to disable any delay, you should add the nodelay option to pam_unix)
|
||||||
|
auth optional pam_faildelay.so delay=3000000
|
||||||
|
|
||||||
|
# Outputs an issue file prior to each login prompt (Replaces the
|
||||||
|
# ISSUE_FILE option from login.defs). Uncomment for use
|
||||||
|
# auth required pam_issue.so issue=/etc/issue
|
||||||
|
|
||||||
|
# Disallows root logins except on tty's listed in /etc/securetty
|
||||||
|
# (Replaces the `CONSOLE' setting from login.defs)
|
||||||
|
#
|
||||||
|
# With the default control of this module:
|
||||||
|
# [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die]
|
||||||
|
# root will not be prompted for a password on insecure lines.
|
||||||
|
# if an invalid username is entered, a password is prompted (but login
|
||||||
|
# will eventually be rejected)
|
||||||
|
#
|
||||||
|
# You can change it to a "requisite" module if you think root may mis-type
|
||||||
|
# her login and should not be prompted for a password in that case. But
|
||||||
|
# this will leave the system as vulnerable to user enumeration attacks.
|
||||||
|
#
|
||||||
|
# You can change it to a "required" module if you think it permits to
|
||||||
|
# guess valid user names of your system (invalid user names are considered
|
||||||
|
# as possibly being root on insecure lines), but root passwords may be
|
||||||
|
# communicated over insecure lines.
|
||||||
|
auth [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die] pam_securetty.so
|
||||||
|
|
||||||
|
# Disallows other than root logins when /etc/nologin exists
|
||||||
|
# (Replaces the `NOLOGINS_FILE' option from login.defs)
|
||||||
|
auth requisite pam_nologin.so
|
||||||
|
|
||||||
|
# SELinux needs to be the first session rule. This ensures that any
|
||||||
|
# lingering context has been cleared. Without this it is possible
|
||||||
|
# that a module could execute code in the wrong domain.
|
||||||
|
# When the module is present, "required" would be sufficient (When SELinux
|
||||||
|
# is disabled, this returns success.)
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
|
||||||
|
|
||||||
|
# Sets the loginuid process attribute
|
||||||
|
session required pam_loginuid.so
|
||||||
|
|
||||||
|
# SELinux needs to intervene at login time to ensure that the process
|
||||||
|
# starts in the proper default security context. Only sessions which are
|
||||||
|
# intended to run in the user's context should be run after this.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
|
||||||
|
# When the module is present, "required" would be sufficient (When SELinux
|
||||||
|
# is disabled, this returns success.)
|
||||||
|
|
||||||
|
# This module parses environment configuration file(s)
|
||||||
|
# and also allows you to use an extended config
|
||||||
|
# file /etc/security/pam_env.conf.
|
||||||
|
#
|
||||||
|
# parsing /etc/environment needs "readenv=1"
|
||||||
|
session required pam_env.so readenv=1
|
||||||
|
# locale variables are also kept into /etc/default/locale in etch
|
||||||
|
# reading this file *in addition to /etc/environment* does not hurt
|
||||||
|
session required pam_env.so readenv=1 envfile=/etc/default/locale
|
||||||
|
|
||||||
|
# Standard Un*x authentication.
|
||||||
|
@include common-auth-sonic
|
||||||
|
|
||||||
|
# This allows certain extra groups to be granted to a user
|
||||||
|
# based on things like time of day, tty, service, and user.
|
||||||
|
# Please edit /etc/security/group.conf to fit your needs
|
||||||
|
# (Replaces the `CONSOLE_GROUPS' option in login.defs)
|
||||||
|
auth optional pam_group.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/time.conf if you need to set
|
||||||
|
# time restraint on logins.
|
||||||
|
# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs
|
||||||
|
# as well as /etc/porttime)
|
||||||
|
# account requisite pam_time.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/access.conf if you need to
|
||||||
|
# set access limits.
|
||||||
|
# (Replaces /etc/login.access file)
|
||||||
|
# account required pam_access.so
|
||||||
|
|
||||||
|
# Sets up user limits according to /etc/security/limits.conf
|
||||||
|
# (Replaces the use of /etc/limits in old login)
|
||||||
|
session required pam_limits.so
|
||||||
|
|
||||||
|
# Prints the last login info upon successful login
|
||||||
|
# (Replaces the `LASTLOG_ENAB' option from login.defs)
|
||||||
|
session optional pam_lastlog.so
|
||||||
|
|
||||||
|
# Prints the message of the day upon successful login.
|
||||||
|
# (Replaces the `MOTD_FILE' option in login.defs)
|
||||||
|
# This includes a dynamically generated part from /run/motd.dynamic
|
||||||
|
# and a static (admin-editable) part from /etc/motd.
|
||||||
|
session optional pam_motd.so motd=/run/motd.dynamic
|
||||||
|
session optional pam_motd.so noupdate
|
||||||
|
|
||||||
|
# Prints the status of the user's mailbox upon successful login
|
||||||
|
# (Replaces the `MAIL_CHECK_ENAB' option from login.defs).
|
||||||
|
#
|
||||||
|
# This also defines the MAIL environment variable
|
||||||
|
# However, userdel also needs MAIL_DIR and MAIL_FILE variables
|
||||||
|
# in /etc/login.defs to make sure that removing a user
|
||||||
|
# also removes the user's mail spool file.
|
||||||
|
# See comments in /etc/login.defs
|
||||||
|
session optional pam_mail.so standard
|
||||||
|
|
||||||
|
# Create a new session keyring.
|
||||||
|
session optional pam_keyinit.so force revoke
|
||||||
|
|
||||||
|
# Standard Un*x account and session
|
||||||
|
@include common-account
|
||||||
|
@include common-session
|
||||||
|
@include common-password
|
@ -0,0 +1,116 @@
|
|||||||
|
#
|
||||||
|
# The PAM configuration file for the Shadow `login' service
|
||||||
|
#
|
||||||
|
|
||||||
|
# Enforce a minimal delay in case of failure (in microseconds).
|
||||||
|
# (Replaces the `FAIL_DELAY' setting from login.defs)
|
||||||
|
# Note that other modules may require another minimal delay. (for example,
|
||||||
|
# to disable any delay, you should add the nodelay option to pam_unix)
|
||||||
|
auth optional pam_faildelay.so delay=3000000
|
||||||
|
|
||||||
|
# Outputs an issue file prior to each login prompt (Replaces the
|
||||||
|
# ISSUE_FILE option from login.defs). Uncomment for use
|
||||||
|
# auth required pam_issue.so issue=/etc/issue
|
||||||
|
|
||||||
|
# Disallows root logins except on tty's listed in /etc/securetty
|
||||||
|
# (Replaces the `CONSOLE' setting from login.defs)
|
||||||
|
#
|
||||||
|
# With the default control of this module:
|
||||||
|
# [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die]
|
||||||
|
# root will not be prompted for a password on insecure lines.
|
||||||
|
# if an invalid username is entered, a password is prompted (but login
|
||||||
|
# will eventually be rejected)
|
||||||
|
#
|
||||||
|
# You can change it to a "requisite" module if you think root may mis-type
|
||||||
|
# her login and should not be prompted for a password in that case. But
|
||||||
|
# this will leave the system as vulnerable to user enumeration attacks.
|
||||||
|
#
|
||||||
|
# You can change it to a "required" module if you think it permits to
|
||||||
|
# guess valid user names of your system (invalid user names are considered
|
||||||
|
# as possibly being root on insecure lines), but root passwords may be
|
||||||
|
# communicated over insecure lines.
|
||||||
|
auth [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die] pam_securetty.so
|
||||||
|
|
||||||
|
# Disallows other than root logins when /etc/nologin exists
|
||||||
|
# (Replaces the `NOLOGINS_FILE' option from login.defs)
|
||||||
|
auth requisite pam_nologin.so
|
||||||
|
|
||||||
|
# SELinux needs to be the first session rule. This ensures that any
|
||||||
|
# lingering context has been cleared. Without this it is possible
|
||||||
|
# that a module could execute code in the wrong domain.
|
||||||
|
# When the module is present, "required" would be sufficient (When SELinux
|
||||||
|
# is disabled, this returns success.)
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
|
||||||
|
|
||||||
|
# Sets the loginuid process attribute
|
||||||
|
session required pam_loginuid.so
|
||||||
|
|
||||||
|
# SELinux needs to intervene at login time to ensure that the process
|
||||||
|
# starts in the proper default security context. Only sessions which are
|
||||||
|
# intended to run in the user's context should be run after this.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
|
||||||
|
# When the module is present, "required" would be sufficient (When SELinux
|
||||||
|
# is disabled, this returns success.)
|
||||||
|
|
||||||
|
# This module parses environment configuration file(s)
|
||||||
|
# and also allows you to use an extended config
|
||||||
|
# file /etc/security/pam_env.conf.
|
||||||
|
#
|
||||||
|
# parsing /etc/environment needs "readenv=1"
|
||||||
|
session required pam_env.so readenv=1
|
||||||
|
# locale variables are also kept into /etc/default/locale in etch
|
||||||
|
# reading this file *in addition to /etc/environment* does not hurt
|
||||||
|
session required pam_env.so readenv=1 envfile=/etc/default/locale
|
||||||
|
|
||||||
|
# Standard Un*x authentication.
|
||||||
|
@include common-auth
|
||||||
|
|
||||||
|
# This allows certain extra groups to be granted to a user
|
||||||
|
# based on things like time of day, tty, service, and user.
|
||||||
|
# Please edit /etc/security/group.conf to fit your needs
|
||||||
|
# (Replaces the `CONSOLE_GROUPS' option in login.defs)
|
||||||
|
auth optional pam_group.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/time.conf if you need to set
|
||||||
|
# time restraint on logins.
|
||||||
|
# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs
|
||||||
|
# as well as /etc/porttime)
|
||||||
|
# account requisite pam_time.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/access.conf if you need to
|
||||||
|
# set access limits.
|
||||||
|
# (Replaces /etc/login.access file)
|
||||||
|
# account required pam_access.so
|
||||||
|
|
||||||
|
# Sets up user limits according to /etc/security/limits.conf
|
||||||
|
# (Replaces the use of /etc/limits in old login)
|
||||||
|
session required pam_limits.so
|
||||||
|
|
||||||
|
# Prints the last login info upon successful login
|
||||||
|
# (Replaces the `LASTLOG_ENAB' option from login.defs)
|
||||||
|
session optional pam_lastlog.so
|
||||||
|
|
||||||
|
# Prints the message of the day upon successful login.
|
||||||
|
# (Replaces the `MOTD_FILE' option in login.defs)
|
||||||
|
# This includes a dynamically generated part from /run/motd.dynamic
|
||||||
|
# and a static (admin-editable) part from /etc/motd.
|
||||||
|
session optional pam_motd.so motd=/run/motd.dynamic
|
||||||
|
session optional pam_motd.so noupdate
|
||||||
|
|
||||||
|
# Prints the status of the user's mailbox upon successful login
|
||||||
|
# (Replaces the `MAIL_CHECK_ENAB' option from login.defs).
|
||||||
|
#
|
||||||
|
# This also defines the MAIL environment variable
|
||||||
|
# However, userdel also needs MAIL_DIR and MAIL_FILE variables
|
||||||
|
# in /etc/login.defs to make sure that removing a user
|
||||||
|
# also removes the user's mail spool file.
|
||||||
|
# See comments in /etc/login.defs
|
||||||
|
session optional pam_mail.so standard
|
||||||
|
|
||||||
|
# Create a new session keyring.
|
||||||
|
session optional pam_keyinit.so force revoke
|
||||||
|
|
||||||
|
# Standard Un*x account and session
|
||||||
|
@include common-account
|
||||||
|
@include common-session
|
||||||
|
@include common-password
|
@ -0,0 +1,56 @@
|
|||||||
|
#THIS IS AN AUTO-GENERATED FILE
|
||||||
|
# Generated from: /usr/share/sonic/templates/radius_nss.conf.j2
|
||||||
|
# RADIUS NSS Configuration File
|
||||||
|
#
|
||||||
|
# Debug: on|off|trace
|
||||||
|
# Default: off
|
||||||
|
#
|
||||||
|
# debug=on
|
||||||
|
debug=on
|
||||||
|
|
||||||
|
#
|
||||||
|
# User Privilege:
|
||||||
|
# Default:
|
||||||
|
# user_priv=15;pw_info=remote_user_su;gid=1000;group=sudo,docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=1;pw_info=remote_user;gid=999;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# user_priv=15;pw_info=remote_user_su;gid=1000;group=sudo,docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=7;pw_info=netops;gid=999;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
# user_priv=1;pw_info=operator;gid=100;group=docker;shell=/usr/bin/sonic-launch-shell
|
||||||
|
#
|
||||||
|
|
||||||
|
# many_to_one:
|
||||||
|
# y: Map RADIUS users to one local user per privilege.
|
||||||
|
# n: Create local user account on first successful authentication.
|
||||||
|
# Default: n
|
||||||
|
#
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# many_to_one=y
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_disallow:
|
||||||
|
# y: Do not allow unconfirmed users (users created before authentication)
|
||||||
|
# n: Allow unconfirmed users.
|
||||||
|
# Default: n
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# unconfirmed_disallow=y
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_ageout:
|
||||||
|
# <seconds>: Wait time before purging unconfirmed users
|
||||||
|
# Default: 600
|
||||||
|
#
|
||||||
|
|
||||||
|
# Eg:
|
||||||
|
# unconfirmed_ageout=900
|
||||||
|
#
|
||||||
|
|
||||||
|
# unconfirmed_regexp:
|
||||||
|
# <regexp>: The RE to match the command line of processes for which the
|
||||||
|
# creation of unconfirmed users are to be allowed.
|
||||||
|
# Default: (.*: <user> \[priv\])|(.*: \[accepted\])
|
||||||
|
# where: <user> is the unconfirmed user.
|
||||||
|
#
|
@ -0,0 +1,55 @@
|
|||||||
|
# PAM configuration for the Secure Shell service
|
||||||
|
|
||||||
|
# Standard Un*x authentication.
|
||||||
|
@include common-auth-sonic
|
||||||
|
|
||||||
|
# Disallow non-root logins when /etc/nologin exists.
|
||||||
|
account required pam_nologin.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/access.conf if you need to set complex
|
||||||
|
# access limits that are hard to express in sshd_config.
|
||||||
|
# account required pam_access.so
|
||||||
|
|
||||||
|
# Standard Un*x authorization.
|
||||||
|
@include common-account
|
||||||
|
|
||||||
|
# SELinux needs to be the first session rule. This ensures that any
|
||||||
|
# lingering context has been cleared. Without this it is possible that a
|
||||||
|
# module could execute code in the wrong domain.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
|
||||||
|
|
||||||
|
# Set the loginuid process attribute.
|
||||||
|
session required pam_loginuid.so
|
||||||
|
|
||||||
|
# Create a new session keyring.
|
||||||
|
session optional pam_keyinit.so force revoke
|
||||||
|
|
||||||
|
# Standard Un*x session setup and teardown.
|
||||||
|
@include common-session
|
||||||
|
|
||||||
|
# Print the message of the day upon successful login.
|
||||||
|
# This includes a dynamically generated part from /run/motd.dynamic
|
||||||
|
# and a static (admin-editable) part from /etc/motd.
|
||||||
|
session optional pam_motd.so motd=/run/motd.dynamic
|
||||||
|
session optional pam_motd.so noupdate
|
||||||
|
|
||||||
|
# Print the status of the user's mailbox upon successful login.
|
||||||
|
session optional pam_mail.so standard noenv # [1]
|
||||||
|
|
||||||
|
# Set up user limits from /etc/security/limits.conf.
|
||||||
|
session required pam_limits.so
|
||||||
|
|
||||||
|
# Read environment variables from /etc/environment and
|
||||||
|
# /etc/security/pam_env.conf.
|
||||||
|
session required pam_env.so # [1]
|
||||||
|
# In Debian 4.0 (etch), locale-related environment variables were moved to
|
||||||
|
# /etc/default/locale, so read that as well.
|
||||||
|
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
|
||||||
|
|
||||||
|
# SELinux needs to intervene at login time to ensure that the process starts
|
||||||
|
# in the proper default security context. Only sessions which are intended
|
||||||
|
# to run in the user's context should be run after this.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
|
||||||
|
|
||||||
|
# Standard Un*x password updating.
|
||||||
|
@include common-password
|
@ -0,0 +1,55 @@
|
|||||||
|
# PAM configuration for the Secure Shell service
|
||||||
|
|
||||||
|
# Standard Un*x authentication.
|
||||||
|
@include common-auth
|
||||||
|
|
||||||
|
# Disallow non-root logins when /etc/nologin exists.
|
||||||
|
account required pam_nologin.so
|
||||||
|
|
||||||
|
# Uncomment and edit /etc/security/access.conf if you need to set complex
|
||||||
|
# access limits that are hard to express in sshd_config.
|
||||||
|
# account required pam_access.so
|
||||||
|
|
||||||
|
# Standard Un*x authorization.
|
||||||
|
@include common-account
|
||||||
|
|
||||||
|
# SELinux needs to be the first session rule. This ensures that any
|
||||||
|
# lingering context has been cleared. Without this it is possible that a
|
||||||
|
# module could execute code in the wrong domain.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
|
||||||
|
|
||||||
|
# Set the loginuid process attribute.
|
||||||
|
session required pam_loginuid.so
|
||||||
|
|
||||||
|
# Create a new session keyring.
|
||||||
|
session optional pam_keyinit.so force revoke
|
||||||
|
|
||||||
|
# Standard Un*x session setup and teardown.
|
||||||
|
@include common-session
|
||||||
|
|
||||||
|
# Print the message of the day upon successful login.
|
||||||
|
# This includes a dynamically generated part from /run/motd.dynamic
|
||||||
|
# and a static (admin-editable) part from /etc/motd.
|
||||||
|
session optional pam_motd.so motd=/run/motd.dynamic
|
||||||
|
session optional pam_motd.so noupdate
|
||||||
|
|
||||||
|
# Print the status of the user's mailbox upon successful login.
|
||||||
|
session optional pam_mail.so standard noenv # [1]
|
||||||
|
|
||||||
|
# Set up user limits from /etc/security/limits.conf.
|
||||||
|
session required pam_limits.so
|
||||||
|
|
||||||
|
# Read environment variables from /etc/environment and
|
||||||
|
# /etc/security/pam_env.conf.
|
||||||
|
session required pam_env.so # [1]
|
||||||
|
# In Debian 4.0 (etch), locale-related environment variables were moved to
|
||||||
|
# /etc/default/locale, so read that as well.
|
||||||
|
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
|
||||||
|
|
||||||
|
# SELinux needs to intervene at login time to ensure that the process starts
|
||||||
|
# in the proper default security context. Only sessions which are intended
|
||||||
|
# to run in the user's context should be run after this.
|
||||||
|
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
|
||||||
|
|
||||||
|
# Standard Un*x password updating.
|
||||||
|
@include common-password
|
@ -0,0 +1,23 @@
|
|||||||
|
# Configuration for libnss-tacplus
|
||||||
|
|
||||||
|
# debug - If you want to open debug log, set it on
|
||||||
|
# Default: off
|
||||||
|
# debug=on
|
||||||
|
debug=on
|
||||||
|
|
||||||
|
# src_ip - set source address of TACACS+ protocol packets
|
||||||
|
# Default: None (auto source ip address)
|
||||||
|
# src_ip=2.2.2.2
|
||||||
|
|
||||||
|
# server - set ip address, tcp port, secret string and timeout for TACACS+ servers
|
||||||
|
# Default: None (no TACACS+ server)
|
||||||
|
# server=1.1.1.1:49,secret=test,timeout=3
|
||||||
|
|
||||||
|
# user_priv - set the map between TACACS+ user privilege and local user's passwd
|
||||||
|
# Default:
|
||||||
|
# user_priv=15;pw_info=remote_user_su;gid=1000;group=sudo,docker;shell=/bin/bash
|
||||||
|
# user_priv=1;pw_info=remote_user;gid=999;group=docker;shell=/bin/bash
|
||||||
|
|
||||||
|
# many_to_one - create one local user for many TACACS+ users which has the same privilege
|
||||||
|
# Default: many_to_one=n
|
||||||
|
# many_to_one=y
|
181
src/sonic-host-services/tests/hostcfgd/test_radius_vectors.py
Normal file
181
src/sonic-host-services/tests/hostcfgd/test_radius_vectors.py
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
from unittest.mock import call
|
||||||
|
|
||||||
|
"""
|
||||||
|
hostcfgd test radius vector
|
||||||
|
"""
|
||||||
|
HOSTCFGD_TEST_RADIUS_VECTOR = [
|
||||||
|
[
|
||||||
|
"RADIUS",
|
||||||
|
{
|
||||||
|
"config_db": {
|
||||||
|
"DEVICE_METADATA": {
|
||||||
|
"localhost": {
|
||||||
|
"hostname": "radius",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FEATURE": {
|
||||||
|
"dhcp_relay": {
|
||||||
|
"auto_restart": "enabled",
|
||||||
|
"has_global_scope": "True",
|
||||||
|
"has_per_asic_scope": "False",
|
||||||
|
"has_timer": "False",
|
||||||
|
"high_mem_alert": "disabled",
|
||||||
|
"set_owner": "kube",
|
||||||
|
"state": "enabled"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"KDUMP": {
|
||||||
|
"config": {
|
||||||
|
"enabled": "false",
|
||||||
|
"num_dumps": "3",
|
||||||
|
"memory": "0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AAA": {
|
||||||
|
"authentication": {
|
||||||
|
"login": "radius,local",
|
||||||
|
"debug": "True",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RADIUS": {
|
||||||
|
"global": {
|
||||||
|
"nas_ip": "10.10.10.10",
|
||||||
|
"auth_port": "1645",
|
||||||
|
"auth_type": "mschapv2",
|
||||||
|
"retransmit": "2",
|
||||||
|
"timeout": "3",
|
||||||
|
"passkey": "pass",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RADIUS_SERVER": {
|
||||||
|
"10.10.10.1": {
|
||||||
|
"auth_type": "pap",
|
||||||
|
"retransmit": "1",
|
||||||
|
"timeout": "1",
|
||||||
|
"passkey": "pass1",
|
||||||
|
},
|
||||||
|
"10.10.10.2": {
|
||||||
|
"auth_type": "chap",
|
||||||
|
"retransmit": "2",
|
||||||
|
"timeout": "2",
|
||||||
|
"passkey": "pass2",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"expected_config_db": {
|
||||||
|
"DEVICE_METADATA": {
|
||||||
|
"localhost": {
|
||||||
|
"hostname": "radius",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FEATURE": {
|
||||||
|
"dhcp_relay": {
|
||||||
|
"auto_restart": "enabled",
|
||||||
|
"has_global_scope": "True",
|
||||||
|
"has_per_asic_scope": "False",
|
||||||
|
"has_timer": "False",
|
||||||
|
"high_mem_alert": "disabled",
|
||||||
|
"set_owner": "kube",
|
||||||
|
"state": "enabled"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"AAA": {
|
||||||
|
"authentication": {
|
||||||
|
"login": "radius,local",
|
||||||
|
"debug": "True",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RADIUS": {
|
||||||
|
"global": {
|
||||||
|
"nas_ip": "10.10.10.10",
|
||||||
|
"auth_port": "1645",
|
||||||
|
"auth_type": "mschapv2",
|
||||||
|
"retransmit": "2",
|
||||||
|
"timeout": "3",
|
||||||
|
"passkey": "pass",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"RADIUS_SERVER": {
|
||||||
|
"10.10.10.1": {
|
||||||
|
"auth_type": "pap",
|
||||||
|
"retransmit": "1",
|
||||||
|
"timeout": "1",
|
||||||
|
"passkey": "pass1",
|
||||||
|
},
|
||||||
|
"10.10.10.2": {
|
||||||
|
"auth_type": "chap",
|
||||||
|
"retransmit": "2",
|
||||||
|
"timeout": "2",
|
||||||
|
"passkey": "pass2",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"expected_subprocess_calls": [
|
||||||
|
call("service aaastatsd start", shell=True),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"LOCAL",
|
||||||
|
{
|
||||||
|
"config_db": {
|
||||||
|
"DEVICE_METADATA": {
|
||||||
|
"localhost": {
|
||||||
|
"hostname": "local",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FEATURE": {
|
||||||
|
"dhcp_relay": {
|
||||||
|
"auto_restart": "enabled",
|
||||||
|
"has_global_scope": "True",
|
||||||
|
"has_per_asic_scope": "False",
|
||||||
|
"has_timer": "False",
|
||||||
|
"high_mem_alert": "disabled",
|
||||||
|
"set_owner": "kube",
|
||||||
|
"state": "enabled"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"KDUMP": {
|
||||||
|
"config": {
|
||||||
|
"enabled": "false",
|
||||||
|
"num_dumps": "3",
|
||||||
|
"memory": "0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AAA": {
|
||||||
|
"authentication": {
|
||||||
|
"login": "local",
|
||||||
|
"debug": "True",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"expected_config_db": {
|
||||||
|
"DEVICE_METADATA": {
|
||||||
|
"localhost": {
|
||||||
|
"hostname": "local",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"FEATURE": {
|
||||||
|
"dhcp_relay": {
|
||||||
|
"auto_restart": "enabled",
|
||||||
|
"has_global_scope": "True",
|
||||||
|
"has_per_asic_scope": "False",
|
||||||
|
"has_timer": "False",
|
||||||
|
"high_mem_alert": "disabled",
|
||||||
|
"set_owner": "kube",
|
||||||
|
"state": "enabled"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"AAA": {
|
||||||
|
"authentication": {
|
||||||
|
"login": "local",
|
||||||
|
"debug": "True",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"expected_subprocess_calls": [
|
||||||
|
call("service aaastatsd start", shell=True),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user