diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b8e50494fb6..cae4352ea1e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -21,76 +21,6 @@ jobs:
id: matrix
run: ./contrib/ci/get-matrix.py --action
- intgcheck:
- if: github.event_name == 'push' || !contains(github.event.pull_request.labels.*.name, 'Accepted')
- needs: [prepare]
- strategy:
- fail-fast: false
- matrix:
- tag: ${{ fromJson(needs.prepare.outputs.matrix).intgcheck }}
- runs-on: ubuntu-latest
- permissions:
- contents: read
- steps:
- - name: Checkout repository
- uses: actions/checkout@v7
- with:
- path: sssd
-
- - name: Setup containers
- uses: SSSD/sssd-ci-containers/actions/setup@master
- with:
- path: sssd-ci-containers
- tag: ${{ matrix.tag }}
- limit: dns client
- override: |
- services:
- client:
- image: ${REGISTRY}/ci-client-devel:${TAG}
- volumes:
- - ../sssd:/sssd:rw
-
- - name: Run integration tests
- uses: SSSD/sssd-ci-containers/actions/exec@master
- with:
- working-directory: /sssd
- script: ./contrib/ci/run --moderate
-
- - name: Print logs
- uses: next-actions/print-logs@master
- if: always()
- with:
- working-directory: ./sssd/ci-build-debug
- files: |
- test-suite.log
- ci-make-intgcheck.log
- ci-make-distcheck.log
-
- - name: Upload main artifacts
- if: always()
- uses: actions/upload-artifact@v7
- with:
- if-no-files-found: ignore
- name: ${{ matrix.tag }}-intgcheck
- path: |
- ./sssd/var/log/sssd/*.log
- ./sssd/ci-build-debug/ci-*.log
- ./sssd/ci-build-debug/config.log
- ./sssd/ci-build-debug/test-suite.log
- ./sssd/ci-build-debug/ci-mock-result/*.log
- ./sssd/ci-build-debug/src/tests/cwrap/test-suite.log
- ./sssd/ci-install-deps.log
- ./sssd/ci-autoreconf.log
-
- - name: Upload valgrind artifacts
- if: always()
- uses: actions/upload-artifact@v7
- with:
- if-no-files-found: ignore
- name: ${{ matrix.tag }}-intgcheck-valgrind
- path: |
- ./sssd/ci-build-debug/*.valgrind.log
-
system:
if: github.event_name == 'push' || !contains(github.event.pull_request.labels.*.name, 'Accepted')
needs: [prepare]
diff --git a/Makefile.am b/Makefile.am
index c5c25f68f16..32713972e89 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,7 +24,7 @@ if HAVE_MANPAGES
SUBDIRS += src/man
endif
-SUBDIRS += . src/tests/cwrap src/tests/intg src/tests/test_CA \
+SUBDIRS += . src/tests/cwrap src/tests/test_CA \
src/tests/test_ECC_CA src/tools/analyzer
# Some old versions of automake don't define builddir
@@ -4091,51 +4091,6 @@ test_sssd_krb5_localauth_plugin_LDADD = \
$(NULL)
endif
-#####################
-# Integration tests #
-#####################
-
-intgcheck-prepare:
- set -e; \
- rm -Rf intg; \
- $(MKDIR_P) intg/bld; \
- : Use /hopefully/ short prefix to keep D-Bus socket path short; \
- prefix=`mktemp --tmpdir --directory sssd-intg.XXXXXXXX`; \
- $(LN_S) "$$prefix" intg/pfx; \
- cd intg/bld; \
- $(abs_top_srcdir)/configure \
- --prefix="$$prefix" \
- --with-ldb-lib-dir="$$prefix"/lib/ldb \
- --with-pid-path="$$prefix"/run/sssd \
- --enable-intgcheck-reqs \
- --without-selinux \
- --with-session-recording-shell=/bin/false \
- $(INTGCHECK_CONFIGURE_FLAGS) \
- CFLAGS="-O2 -g $$CFLAGS -DINTGCHECK_BUILD"; \
- $(MAKE) $(AM_MAKEFLAGS) ; \
- $(MAKE) $(AM_MAKEFLAGS) test_ssh_client; \
- : Force single-thread install to workaround concurrency issues; \
- $(MAKE) $(AM_MAKEFLAGS) -j1 install; \
- : Remove .la files from LDB module directory to avoid loader warnings; \
- rm "$$prefix"/lib/ldb/*.la; \
- cd ../..
-
-intgcheck-run:
- set -e; \
- if [ ! -d intg/pfx ]; then $(MAKE) intgcheck-prepare; fi; \
- cd intg/bld; \
- $(MAKE) $(AM_MAKEFLAGS) -C src/tests/intg intgcheck-installed; \
- cd ../..
-
-intgcheck-clean:
- set -e; \
- prefix=`readlink -e intg/pfx`; \
- rm -Rf "$$prefix" intg
-
-intgcheck:
- $(MAKE) intgcheck-prepare
- $(MAKE) intgcheck-run
- $(MAKE) intgcheck-clean
####################
# Client Libraries #
diff --git a/configure.ac b/configure.ac
index 39a9ebc91df..8d2fdb313ba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -235,7 +235,6 @@ m4_include([src/external/sasl.m4])
m4_include([src/external/libnfsidmap.m4])
m4_include([src/external/cwrap.m4])
m4_include([src/external/libresolv.m4])
-m4_include([src/external/intgcheck.m4])
m4_include([src/external/systemtap.m4])
m4_include([src/external/service.m4])
m4_include([src/external/test_ca.m4])
@@ -552,7 +551,7 @@ AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
src/examples/logrotate
src/sysv/sssd src/sysv/gentoo/sssd src/sysv/gentoo/sssd-kcm
po/Makefile.in src/man/Makefile src/tests/cwrap/Makefile
- src/tests/intg/Makefile src/tests/test_CA/Makefile
+ src/tests/test_CA/Makefile
src/tests/test_CA/intermediate_CA/Makefile
src/tests/test_ECC_CA/Makefile
src/lib/ipa_hbac/ipa_hbac.pc src/lib/ipa_hbac/ipa_hbac.doxy
diff --git a/contrib/ci/deps.sh b/contrib/ci/deps.sh
index c86f106c8f6..a3c32d6f590 100644
--- a/contrib/ci/deps.sh
+++ b/contrib/ci/deps.sh
@@ -26,9 +26,6 @@ declare -a DEPS_LIST=(
valgrind
)
-# "Integration tests dependencies satisfied" flag
-declare DEPS_INTGCHECK_SATISFIED=true
-
if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then
declare _DEPS_LIST_SPEC
DEPS_LIST+=(
@@ -150,7 +147,6 @@ if [[ "$DISTRO_BRANCH" == -debian-* ]]; then
libsubid-dev
)
- DEPS_INTGCHECK_SATISFIED=true
fi
declare -a -r DEPS_LIST
diff --git a/contrib/ci/get-matrix.py b/contrib/ci/get-matrix.py
index b2b79555c8c..07778e31f1f 100755
--- a/contrib/ci/get-matrix.py
+++ b/contrib/ci/get-matrix.py
@@ -66,7 +66,6 @@ def get_centos_matrix():
centos = sorted(get_centos_matrix())
matrix = {
- 'intgcheck': [*fedora, *centos],
'multihost': [*fedora, *centos],
}
diff --git a/contrib/ci/run b/contrib/ci/run
index 43fb60a8c84..49a37656ad9 100755
--- a/contrib/ci/run
+++ b/contrib/ci/run
@@ -135,7 +135,6 @@ function build_debug()
declare -r valgrind_test_pattern+="*/double_semicolon_test)"
export CFLAGS="$DEBUG_CFLAGS"
declare test_dir
- declare intgcheck_configure_args
declare status
test_dir=`mktemp --directory /dev/shm/ci-test-dir.XXXXXXXX`
@@ -163,18 +162,6 @@ function build_debug()
mv "$test_dir" ci-test-dir
((status == 0))
- if "$MODERATE"; then
- if "$DEPS_INTGCHECK_SATISFIED"; then
- printf -v intgcheck_configure_args " %q" \
- "${CONFIGURE_ARG_LIST[@]}"
- stage make-intgcheck make -j $CPU_NUM intgcheck \
- INTGCHECK_CONFIGURE_FLAGS=" \
- $intgcheck_configure_args"
- fi
-
- ((status == 0))
- fi
-
unset CFLAGS
}
diff --git a/src/external/intgcheck.m4 b/src/external/intgcheck.m4
deleted file mode 100644
index 1446a7cb4bf..00000000000
--- a/src/external/intgcheck.m4
+++ /dev/null
@@ -1,87 +0,0 @@
-AC_CHECK_PROG([HAVE_FAKEROOT], [fakeroot], [yes], [no])
-
-dnl Check for variable and fail unless value is "yes"
-dnl The second argument will be printed in error message in case of error
-dnl Usage:
-dnl SSS_INTGCHECK_REQ(variable, message)
-
-AC_DEFUN([SSS_INTGCHECK_REQ], [
- AS_IF([test x$$1 = xyes], , [
- AC_MSG_ERROR([cannot enable integration tests: $2 not found])])
-])
-
-dnl Check for python variable and fail/warn unless value is "yes"
-dnl The second argument will be printed in error message in case of error
-dnl Any value in 3rd argument will make change error to info
-dnl Usage:
-dnl SSS_INTGCHECK_PYTHON_REQ(variable, message, [non_fatal])
-
-AC_DEFUN([SSS_INTGCHECK_PYTHON_REQ], [
- AS_IF([test x$$1 = xyes], [],
- [sss_have_py_intg_deps=no
- AS_IF([test -n "$3"],
- [AC_MSG_NOTICE([missing python dependency for integration tests: $2 not found])],
- [AC_MSG_ERROR([cannot enable integration tests: $2 not found])])
- ])
-])
-
-dnl Check for variable and fail unless value is "yes"
-dnl The second argument will be printed in error message in case of error
-dnl Usage:
-dnl SSS_CHECK_PYTHON_INTG_REQ(python_version, [non_fatal])
-AC_DEFUN([SSS_CHECK_PYTHON_INTG_REQ], [
- sss_have_py_intg_deps="no"
-
- SSS_INTGCHECK_PYTHON_REQ([HAVE_PYTHON$1_BINDINGS],
- [sssd python$1 bindings], [$2])
-
- AS_IF([test x$HAVE_PYTHON$1_BINDINGS = xyes],
- [SSS_CHECK_PYTEST([$PYTHON$1], [PY$1_PYTEST])
- []AM_PYTHON$1_MODULE([ldap])
- []AM_PYTHON$1_MODULE([ldb])
- []AM_PYTHON$1_MODULE([requests])
- []AM_PYTHON$1_MODULE([dbus])
- []AM_PYTHON$1_MODULE([psutil])
-
- sss_have_py_intg_deps="yes"
-
- SSS_INTGCHECK_PYTHON_REQ([HAVE_PY$1_PYTEST],
- [python$1 pytest], [$2])
- SSS_INTGCHECK_PYTHON_REQ([HAVE_PY$1MOD_LDAP],
- [python$1 module ldap], [$2])
- SSS_INTGCHECK_PYTHON_REQ([HAVE_PY$1MOD_LDB],
- [python$1 module ldb], [$2])
- SSS_INTGCHECK_PYTHON_REQ([HAVE_PY$1MOD_REQUESTS],
- [python$1 module requests], [$2])
- SSS_INTGCHECK_PYTHON_REQ([HAVE_PY$1MOD_DBUS],
- [python$1 module dbus], [$2])
- SSS_INTGCHECK_PYTHON_REQ([HAVE_PY$1MOD_PSUTIL],
- [python$1 module psutil], [$2])])
-
- AS_IF([test "x$sss_have_py_intg_deps" = xyes],
- [HAVE_PYTHON_INTG_DEPS=yes
- PYTHON_EXEC_INTG=$PYTHON$1
- AC_SUBST(PYTHON_EXEC_INTG)],
- [HAVE_PYTHON_INTG_DEPS=no])
- unset sss_have_py_intg_deps
-])
-
-AC_DEFUN([SSS_ENABLE_INTGCHECK_REQS], [
- AC_ARG_ENABLE(intgcheck-reqs,
- [AS_HELP_STRING([--enable-intgcheck-reqs],
- [enable checking for integration test requirements [default=no]])],
- [enable_intgcheck_reqs="$enableval"],
- [enable_intgcheck_reqs="no"])
- if test x"$enable_intgcheck_reqs" = xyes; then
- SSS_INTGCHECK_REQ([HAVE_UID_WRAPPER], [uid_wrapper])
- SSS_INTGCHECK_REQ([HAVE_NSS_WRAPPER], [nss_wrapper])
- SSS_INTGCHECK_REQ([HAVE_PAM_WRAPPER], [pam_wrapper])
- SSS_INTGCHECK_REQ([HAVE_SLAPD], [slapd])
- SSS_INTGCHECK_REQ([HAVE_LDAPMODIFY], [ldapmodify])
- SSS_INTGCHECK_REQ([HAVE_FAKEROOT], [fakeroot])
-
- SSS_CHECK_PYTHON_INTG_REQ([3])
- fi
-])
-
-AM_CONDITIONAL([INTG_BUILD], [test x"$enable_intgcheck_reqs" = xyes])
diff --git a/src/tests/intg/.config/screenrc b/src/tests/intg/.config/screenrc
deleted file mode 100644
index fe1e4248a63..00000000000
--- a/src/tests/intg/.config/screenrc
+++ /dev/null
@@ -1,23 +0,0 @@
-autodetach on
-defscrollback 1024
-startup_message off
-nethack on
-vbell off
-vbell_msg " -- Bell,Bell!! -- "
-multiuser off
-msgminwait 0
-msgwait 10
-
-defutf8 on
-defencoding utf8
-
-hardstatus string '%{gk}[ %{G}%H %{g}][%= %{wk}%?%-Lw%?%{=b kR}(%{W}%n*%f %t%?(%u)%?%{=b kR})%{= kw}%?%+Lw%?%?%= %{g}]%{=b C}[ %d/%m %c ]%{W}'
-hardstatus alwayslastline
-
-setenv LD_LIBRARY_PATH "$_LD_LIBRARY_PATH"
-setenv LD_PRELOAD "$_LD_PRELOAD"
-
-screen -t / 0 sh -c 'cd $ROOT_DIR; exec "${SHELL:-sh}"'
-screen -t /etc 1 sh -c 'cd $ROOT_DIR/etc; exec "${SHELL:-sh}"'
-screen -t sssd_cache 3 sh -c 'cd $ROOT_DIR/var/lib/sss/db; exec "${SHELL:-sh}"'
-screen -t sssd_log 2 sh -c 'cd $ROOT_DIR/var/log/sssd; exec "${SHELL:-sh}"'
diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
deleted file mode 100644
index 734050a3153..00000000000
--- a/src/tests/intg/Makefile.am
+++ /dev/null
@@ -1,216 +0,0 @@
-AM_CFLAGS = $(my_CFLAGS)
-dist_noinst_DATA = \
- __init__.py \
- config.py.m4 \
- util.py \
- sssd_nss.py \
- sssd_id.py \
- sssd_ldb.py \
- sssd_netgroup.py \
- sssd_passwd.py \
- sssd_group.py \
- ds.py \
- ds_openldap.py \
- ent.py \
- ldap_ent.py \
- util.py \
- files_ops.py \
- kdc.py \
- krb5utils.py \
- data/ad_data.ldif \
- data/ad_schema.ldif \
- data/cert_schema.ldif \
- data/ssh_schema.ldif \
- data/sudo_schema.ldif \
- test_pam_responder.py \
- conftest.py \
- sssd_hosts.py \
- sssd_nets.py \
- $(NULL)
-
-EXTRA_DIST = data/cwrap-dbus-system.conf.in
-
-dbussysconfdir = $(sysconfdir)/dbus-1
-dbusservicedir = $(datadir)/dbus-1/system-services
-
-if INTG_BUILD
-lib_LTLIBRARIES = getsockopt_wrapper.la
-
-getsockopt_wrapper_la_SOURCES = \
- getsockopt_wrapper.c
-getsockopt_wrapper_la_CFLAGS = \
- $(AM_CFLAGS)
-getsockopt_wrapper_la_LIBADD = \
- $(LIBADD_DL) \
- $(NULL)
-getsockopt_wrapper_la_LDFLAGS = \
- -avoid-version \
- -module
-
-bin_PROGRAMS = sss_netgroup_thread_test
-
-sss_netgroup_thread_test_SOURCES = \
- sss_netgroup_thread_test.c \
- $(NULL)
-sss_netgroup_thread_test_CFLAGS = \
- $(AM_CFLAGS) \
- $(NULL)
-sss_netgroup_thread_test_LDADD = \
- -lpthread \
- $(NULL)
-
-nsslib_LTLIBRARIES = libnss_call.la
-libnss_call_la_SOURCES = \
- nss_call.c \
- $(NULL)
-libnss_call_la_LDFLAGS = \
- -module \
- -version-info 2:0:0 \
- $(NULL)
-
-dist_dbussysconf_DATA = cwrap-dbus-system.conf
-
-install-data-hook:
- $(MKDIR_P) $(DESTDIR)$(runstatedir)/dbus
- $(MKDIR_P) $(DESTDIR)$(sysconfdir)/session.d
-
-endif
-
-if BUILD_KCM_RENEWAL
-KCM_RENEW = "enabled"
-else
-KCM_RENEW = "disabled"
-endif
-
-cwrap-dbus-system.conf: data/cwrap-dbus-system.conf.in Makefile
- $(SED) -e "s!@runstatedir[@]!$(runstatedir)!" \
- -e "s!@dbusservicedir[@]!$(dbusservicedir)!" \
- $< > $@
-
-config.py: config.py.m4
- m4 -D "prefix=\`$(prefix)'" \
- -D "sysconfdir=\`$(sysconfdir)'" \
- -D "nsslibdir=\`$(nsslibdir)'" \
- -D "dbpath=\`$(dbpath)'" \
- -D "pubconfpath=\`$(pubconfpath)'" \
- -D "pidpath=\`$(pidpath)'" \
- -D "logpath=\`$(logpath)'" \
- -D "mcpath=\`$(mcpath)'" \
- -D "secdbpath=\`$(secdbpath)'" \
- -D "libexecpath=\`$(libexecdir)'" \
- -D "runstatedir=\`$(runstatedir)'" \
- -D "abs_builddir=\`$(abs_builddir)'" \
- -D "session_recording_shell=\`$(session_recording_shell)'" \
- -D "py3execdir=\`$(py3execdir)'" \
- -D "python3dir=\`$(python3dir)'" \
- $< > $@
-
-root:
- : "Create directory for emulated root's D-Bus cookies."
- : "See http://dbus.freedesktop.org/doc/dbus-specification.html#auth-mechanisms"
- $(MKDIR_P) -m 0700 root/.dbus-keyrings
-
-passwd: root
- echo "root:x:0:0:root:$(abs_builddir)/root:/bin/bash" > $@
-
-group:
- echo "root:x:0:" > $@
-
-PAM_SERVICE_DIR=pam_service_dir
-pam_sss_service:
- $(MKDIR_P) $(PAM_SERVICE_DIR)
- echo "auth required $(DESTDIR)$(pammoddir)/pam_sss.so" > $(PAM_SERVICE_DIR)/$@
- echo "account required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "password required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "session required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
-
-pam_sss_alt_service:
- $(MKDIR_P) $(PAM_SERVICE_DIR)
- echo "auth required $(DESTDIR)$(pammoddir)/pam_sss.so" > $(PAM_SERVICE_DIR)/$@
- echo "account required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "password required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "session required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
-
-pam_sss_sc_required:
- $(MKDIR_P) $(PAM_SERVICE_DIR)
- echo "auth required $(DESTDIR)$(pammoddir)/pam_sss.so require_cert_auth retry=1" > $(PAM_SERVICE_DIR)/$@
- echo "account required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "password required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "session required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
-
-pam_sss_try_sc:
- $(MKDIR_P) $(PAM_SERVICE_DIR)
- echo "auth required $(DESTDIR)$(pammoddir)/pam_sss.so try_cert_auth" > $(PAM_SERVICE_DIR)/$@
- echo "account required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "password required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "session required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
-
-pam_sss_allow_missing_name:
- $(MKDIR_P) $(PAM_SERVICE_DIR)
- echo "auth required $(DESTDIR)$(pammoddir)/pam_sss.so allow_missing_name" > $(PAM_SERVICE_DIR)/$@
- echo "account required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "password required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "session required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
-
-pam_sss_domains:
- $(MKDIR_P) $(PAM_SERVICE_DIR)
- echo "auth sufficient $(DESTDIR)$(pammoddir)/pam_sss.so forward_pass domains=wrong.dom1" > $(PAM_SERVICE_DIR)/$@
- echo "auth sufficient $(DESTDIR)$(pammoddir)/pam_sss.so forward_pass domains=wrong.dom2" >> $(PAM_SERVICE_DIR)/$@
- echo "auth sufficient $(DESTDIR)$(pammoddir)/pam_sss.so forward_pass domains=wrong.dom3" >> $(PAM_SERVICE_DIR)/$@
- echo "auth sufficient $(DESTDIR)$(pammoddir)/pam_sss.so forward_pass domains=krb5_auth" >> $(PAM_SERVICE_DIR)/$@
- echo "auth required pam_deny.so" >> $(PAM_SERVICE_DIR)/$@
- echo "account required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "password required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
- echo "session required $(DESTDIR)$(pammoddir)/pam_sss.so" >> $(PAM_SERVICE_DIR)/$@
-
-CLEANFILES=config.py config.pyc passwd group
-
-clean-local:
- rm -Rf root
- rm -f $(builddir)/cwrap-dbus-system.conf
-
-PAM_CERT_DB_PATH="$(abs_builddir)/../test_CA/SSSD_test_CA.pem"
-SOFTHSM2_CONF="$(abs_builddir)/../test_CA/softhsm2_one.conf"
-SOFTHSM2_TWO_CONF="$(abs_builddir)/../test_CA/softhsm2_two.conf"
-
-intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service pam_sss_sc_required pam_sss_try_sc pam_sss_allow_missing_name pam_sss_domains sss_netgroup_thread_test
- pipepath="$(DESTDIR)$(pipepath)"; \
- if test $${#pipepath} -gt 80; then \
- echo "error: Pipe directory path too long," \
- "D-Bus won't be able to open sockets" >&2; \
- exit 1; \
- fi
- set -e; \
- cd "$(abs_srcdir)"; \
- nss_wrapper=$$(pkg-config --libs nss_wrapper); \
- uid_wrapper=$$(pkg-config --libs uid_wrapper); \
- unset HOME; \
- PATH="$$(dirname -- $(SLAPD)):$$PATH" \
- PATH="$(DESTDIR)$(sbindir):$(DESTDIR)$(bindir):$$PATH" \
- PATH="$$PATH:$(abs_builddir):$(abs_srcdir)" \
- LANG=C \
- PYTHONPATH="$(abs_builddir):$(abs_srcdir)" \
- LDB_MODULES_PATH="$(DESTDIR)$(ldblibdir)" \
- NON_WRAPPED_UID=$$(id -u) \
- LD_PRELOAD="$(libdir)/getsockopt_wrapper.so:$$nss_wrapper:$$uid_wrapper" \
- LD_LIBRARY_PATH="$$LD_LIBRARY_PATH:$(DESTDIR)$(nsslibdir)" \
- NSS_WRAPPER_PASSWD="$(abs_builddir)/passwd" \
- NSS_WRAPPER_GROUP="$(abs_builddir)/group" \
- NSS_WRAPPER_MODULE_SO_PATH="$(DESTDIR)$(nsslibdir)/libnss_sss.so.2" \
- NSS_WRAPPER_MODULE_FN_PREFIX="sss" \
- UID_WRAPPER=1 \
- UID_WRAPPER_ROOT=1 \
- PAM_WRAPPER=0 \
- PAM_WRAPPER_SERVICE_DIR="$(abs_builddir)/$(PAM_SERVICE_DIR)" \
- PAM_WRAPPER_PATH=$$(pkg-config --libs pam_wrapper) \
- PAM_CERT_DB_PATH=$(PAM_CERT_DB_PATH) \
- ABS_SRCDIR=$(abs_srcdir) \
- SOFTHSM2_CONF=$(SOFTHSM2_CONF) \
- SOFTHSM2_TWO_CONF=$(SOFTHSM2_TWO_CONF) \
- KCM_RENEW=$(KCM_RENEW) \
- DBUS_SOCK_DIR="$(DESTDIR)$(runstatedir)/dbus/" \
- DBUS_SESSION_BUS_ADDRESS="unix:path=$$DBUS_SOCK_DIR/fake_socket" \
- DBUS_SYSTEM_BUS_ADDRESS="unix:path=$$DBUS_SOCK_DIR/system_bus_socket" \
- DBUS_SYSTEM_BUS_DEFAULT_ADDRESS="$$DBUS_SYSTEM_BUS_ADDRESS" \
- fakeroot $(PYTHON_EXEC_INTG) -m pytest -v -r a --tb=native $(INTGCHECK_PYTEST_ARGS) .
- rm -f $(DESTDIR)$(logpath)/*
diff --git a/src/tests/intg/__init__.py b/src/tests/intg/__init__.py
deleted file mode 100644
index 882a963146b..00000000000
--- a/src/tests/intg/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-import sys
-import config
-
-LOCAL_PYEXECDIR = config.PY3EXECDIR
-LOCAL_PYDIR = config.PY3DIR
-
-for path in [LOCAL_PYEXECDIR, LOCAL_PYDIR]:
- if path not in sys.path:
- sys.path.insert(0, path)
diff --git a/src/tests/intg/config.py.m4 b/src/tests/intg/config.py.m4
deleted file mode 100644
index d2e0ffeb437..00000000000
--- a/src/tests/intg/config.py.m4
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
-Build configuration variables.
-"""
-
-PREFIX = "prefix"
-SYSCONFDIR = "sysconfdir"
-NSS_MODULE_DIR = "nsslibdir"
-SSSDCONFDIR = SYSCONFDIR + "/sssd"
-CONF_PATH = SSSDCONFDIR + "/sssd.conf"
-CONF_SNIPPET_PATH = SSSDCONFDIR + "/conf.d/01.conf"
-DB_PATH = "dbpath"
-PID_PATH = "pidpath"
-PUBCONF_PATH = "pubconfpath"
-PIDFILE_PATH = PID_PATH + "/sssd.pid"
-LOG_PATH = "logpath"
-MCACHE_PATH = "mcpath"
-SECDB_PATH = "secdbpath"
-LIBEXEC_PATH = "libexecpath"
-RUNSTATEDIR = "runstatedir"
-ABS_BUILDDIR = "abs_builddir"
-SESSION_RECORDING_SHELL = "session_recording_shell"
-PY3EXECDIR = "py3execdir"
-PY3DIR = "python3dir"
diff --git a/src/tests/intg/conftest.py b/src/tests/intg/conftest.py
deleted file mode 100644
index f07a410940e..00000000000
--- a/src/tests/intg/conftest.py
+++ /dev/null
@@ -1 +0,0 @@
-from files_ops import passwd_ops_setup, group_ops_setup # noqa
diff --git a/src/tests/intg/data/ad_data.ldif b/src/tests/intg/data/ad_data.ldif
deleted file mode 100644
index 0d2ec444c33..00000000000
--- a/src/tests/intg/data/ad_data.ldif
+++ /dev/null
@@ -1,815 +0,0 @@
-dn: cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: container
-cn: Users
-description: Default container for upgraded user accounts
-distinguishedName: cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923233930.0Z
-whenChanged: 20140923233930.0Z
-uSNCreated: 5696
-uSNChanged: 5696
-showInAdvancedViewOnly: FALSE
-name: Users
-objectGUID:: 6Gd2SrsmeEiT3Hmh/5hTqw==
-systemFlags: -1946157056
-objectCategory: cn=Container,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=CHILD1$,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: CHILD1$
-distinguishedName: cn=CHILD1$,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923224256.0Z
-whenChanged: 20160423221800.0Z
-uSNCreated: 20732
-uSNChanged: 2181674
-name: CHILD1$
-objectGUID:: ACE60RcYu0iZv4CMYPK+eg==
-userAccountControl: 2080
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 0
-pwdLastSet: 131059234804699243
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EUAQAAA==
-accountExpires: 9223372036854775807
-logonCount: 0
-sAMAccountName: CHILD1$
-sAMAccountType: 805306370
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=krbtgt,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: krbtgt
-description: Key Distribution Center Service Account
-distinguishedName: cn=krbtgt,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923185530.0Z
-uSNCreated: 12324
-memberOf: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-uSNChanged: 12723
-showInAdvancedViewOnly: TRUE
-name: krbtgt
-objectGUID:: F/Yrx8X81ESM6t14mMxcxA==
-userAccountControl: 514
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 0
-pwdLastSet: 130559892182968750
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8E9gEAAA==
-adminCount: 1
-accountExpires: 9223372036854775807
-logonCount: 0
-sAMAccountName: krbtgt
-sAMAccountType: 805306368
-servicePrincipalName: kadmin/changepw
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 20140923185530.0Z
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Domain Computers,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Domain Computers
-description: All workstations and servers joined to the domain
-distinguishedName: cn=Domain Computers,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923234018.0Z
-uSNCreated: 12330
-uSNChanged: 12332
-name: Domain Computers
-objectGUID:: 09VIVs7CDkOMTnLtMkZMUA==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EAwIAAA==
-sAMAccountName: Domain Computers
-sAMAccountType: 268435456
-groupType: -2147483646
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Domain Controllers,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Domain Controllers
-description: All domain controllers in the domain
-distinguishedName: cn=Domain Controllers,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923185530.0Z
-uSNCreated: 12333
-memberOf: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-uSNChanged: 12726
-name: Domain Controllers
-objectGUID:: a6OG+FLmnECf3fAe0a8o6w==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EBAIAAA==
-adminCount: 1
-sAMAccountName: Domain Controllers
-sAMAccountType: 268435456
-groupType: -2147483646
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 20140923185530.0Z
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Schema Admins,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Schema Admins
-description: Designated administrators of the schema
-member: cn=Administrator,cn=Users,dc=example,dc=com
-distinguishedName: cn=Schema Admins,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923185530.0Z
-uSNCreated: 12336
-memberOf: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-uSNChanged: 12708
-name: Schema Admins
-objectGUID:: ONs7cn0OF0uEip0yMnLv2Q==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EBgIAAA==
-adminCount: 1
-sAMAccountName: Schema Admins
-sAMAccountType: 268435456
-groupType: -2147483640
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 20140923185530.0Z
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Enterprise Admins,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Enterprise Admins
-description: Designated administrators of the enterprise
-member: cn=Administrator,cn=Users,dc=example,dc=com
-distinguishedName: cn=Enterprise Admins,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923185530.0Z
-uSNCreated: 12339
-memberOf: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-memberOf: cn=Administrators,cn=Builtin,dc=example,dc=com
-uSNChanged: 12712
-name: Enterprise Admins
-objectGUID:: rD6jEoiL8U6huv7c/OJPwg==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EBwIAAA==
-adminCount: 1
-sAMAccountName: Enterprise Admins
-sAMAccountType: 268435456
-groupType: -2147483640
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 20140923185530.0Z
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Cert Publishers,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Cert Publishers
-description: Members of this group are permitted to publish certificates to the directory
-member: cn=PLUTO,OU=Domain Controllers,dc=example,dc=com
-distinguishedName: cn=Cert Publishers,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923191508.0Z
-uSNCreated: 12342
-memberOf: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-uSNChanged: 12749
-name: Cert Publishers
-objectGUID:: zWTUMdl6tEWA1J0QnPLkRQ==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EBQIAAA==
-sAMAccountName: Cert Publishers
-sAMAccountType: 536870912
-groupType: -2147483644
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Domain Admins,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Domain Admins
-description: Designated administrators of the domain
-member: cn=Administrator,cn=Users,dc=example,dc=com
-distinguishedName: cn=Domain Admins,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923185530.0Z
-uSNCreated: 12345
-memberOf: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-memberOf: cn=Administrators,cn=Builtin,dc=example,dc=com
-uSNChanged: 12711
-name: Domain Admins
-objectGUID:: YxI+YLrC3UeNNsmMnXGTlg==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EAAIAAA==
-adminCount: 1
-sAMAccountName: Domain Admins
-sAMAccountType: 268435456
-groupType: -2147483646
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 20140923185530.0Z
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Domain Users,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Domain Users
-description: All domain users
-distinguishedName: cn=Domain Users,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20150202222731.0Z
-uSNCreated: 12348
-memberOf: cn=Users,cn=Builtin,dc=example,dc=com
-uSNChanged: 213433
-name: Domain Users
-objectGUID:: JRHvlJXoU0+LOYXs3vESow==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EAQIAAA==
-sAMAccountName: Domain Users
-sAMAccountType: 268435456
-groupType: -2147483646
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-msSFU30NisDomain: example
-gidNumber: 100000
-
-dn: cn=Domain Guests,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Domain Guests
-description: All domain guests
-distinguishedName: cn=Domain Guests,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923234018.0Z
-uSNCreated: 12351
-memberOf: cn=Guests,cn=Builtin,dc=example,dc=com
-uSNChanged: 12353
-name: Domain Guests
-objectGUID:: Rx/t/vuPwUGOMoprY1KFog==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EAgIAAA==
-sAMAccountName: Domain Guests
-sAMAccountType: 268435456
-groupType: -2147483646
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Group Policy Creator Owners,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Group Policy Creator Owners
-description: Members in this group can modify group policy for the domain
-member: cn=Administrator,cn=Users,dc=example,dc=com
-distinguishedName: cn=Group Policy Creator Owners,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923234018.0Z
-uSNCreated: 12354
-memberOf: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-uSNChanged: 12391
-name: Group Policy Creator Owners
-objectGUID:: V3HfwcWfZ0yv1br3tRP6bA==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ECAIAAA==
-sAMAccountName: Group Policy Creator Owners
-sAMAccountType: 268435456
-groupType: -2147483646
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=RAS and IAS Servers,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: RAS and IAS Servers
-description: Servers in this group can access remote access properties of users
-distinguishedName: cn=RAS and IAS Servers,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923234018.0Z
-uSNCreated: 12357
-uSNChanged: 12359
-name: RAS and IAS Servers
-objectGUID:: PHyDebZK7UKVG9HG+mT8ng==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EKQIAAA==
-sAMAccountName: RAS and IAS Servers
-sAMAccountType: 536870912
-groupType: -2147483644
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Allowed ROdc Password Replication Group,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Allowed ROdc Password Replication Group
-description: Members in this group can have their passwords replicated to all read-only domain controllers in the domain
-distinguishedName: cn=Allowed ROdc Password Replication Group,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923234018.0Z
-uSNCreated: 12402
-uSNChanged: 12404
-name: Allowed ROdc Password Replication Group
-objectGUID:: pKN3Txn0SUenHm8Z58ZQYA==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EOwIAAA==
-sAMAccountName: Allowed ROdc Password Replication Group
-sAMAccountType: 536870912
-groupType: -2147483644
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Denied ROdc Password Replication Group
-description: Members in this group cannot have their passwords replicated to any read-only domain controllers in the domain
-member: cn=Read-only Domain Controllers,cn=Users,dc=example,dc=com
-member: cn=Group Policy Creator Owners,cn=Users,dc=example,dc=com
-member: cn=Domain Admins,cn=Users,dc=example,dc=com
-member: cn=Cert Publishers,cn=Users,dc=example,dc=com
-member: cn=Enterprise Admins,cn=Users,dc=example,dc=com
-member: cn=Schema Admins,cn=Users,dc=example,dc=com
-member: cn=Domain Controllers,cn=Users,dc=example,dc=com
-member: cn=krbtgt,cn=Users,dc=example,dc=com
-distinguishedName: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923234018.0Z
-uSNCreated: 12405
-uSNChanged: 12433
-name: Denied ROdc Password Replication Group
-objectGUID:: OoOtLxLbXUSdCGKeGvzc7Q==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EPAIAAA==
-sAMAccountName: Denied ROdc Password Replication Group
-sAMAccountType: 536870912
-groupType: -2147483644
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Read-only Domain Controllers,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Read-only Domain Controllers
-description: Members of this group are Read-Only Domain Controllers in the domain
-distinguishedName: cn=Read-only Domain Controllers,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923185530.0Z
-uSNCreated: 12419
-memberOf: cn=Denied ROdc Password Replication Group,cn=Users,dc=example,dc=com
-uSNChanged: 12725
-name: Read-only Domain Controllers
-objectGUID:: GoeeiCJ87UqBN3C9MhqQ3w==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ECQIAAA==
-adminCount: 1
-sAMAccountName: Read-only Domain Controllers
-sAMAccountType: 268435456
-groupType: -2147483646
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 20140923185530.0Z
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Enterprise Read-only Domain Controllers,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: Enterprise Read-only Domain Controllers
-description: Members of this group are Read-Only Domain Controllers in the enterprise
-distinguishedName: cn=Enterprise Read-only Domain Controllers,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234018.0Z
-whenChanged: 20140923234018.0Z
-uSNCreated: 12429
-uSNChanged: 12431
-name: Enterprise Read-only Domain Controllers
-objectGUID:: qHRH+tAgFUy7660VnrFpTA==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8E8gEAAA==
-sAMAccountName: Enterprise Read-only Domain Controllers
-sAMAccountType: 268435456
-groupType: -2147483640
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=DnsAdmins,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: DnsAdmins
-description: DNS Administrators Group
-distinguishedName: cn=DnsAdmins,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234058.0Z
-whenChanged: 20140923234058.0Z
-uSNCreated: 12459
-uSNChanged: 12461
-name: DnsAdmins
-objectGUID:: w4cyv6dWNEGQao3mL5RpTA==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ETQQAAA==
-sAMAccountName: DnsAdmins
-sAMAccountType: 536870912
-groupType: -2147483644
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=DnsUpdateProxy,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: DnsUpdateProxy
-description: DNS clients who are permitted to perform dynamic updates on behalf of some other clients (such as DHCP servers).
-distinguishedName: cn=DnsUpdateProxy,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923234058.0Z
-whenChanged: 20140923234058.0Z
-uSNCreated: 12464
-uSNChanged: 12464
-name: DnsUpdateProxy
-objectGUID:: LMyHGT2RuEG+IGrGL80qMg==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ETgQAAA==
-sAMAccountName: DnsUpdateProxy
-sAMAccountType: 268435456
-groupType: -2147483646
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=user1_dom1-19661,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: user1_dom1-19661
-givenName: user1_dom1-19661
-distinguishedName: cn=user1_dom1-19661,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20160517121016.0Z
-whenChanged: 20160517121017.0Z
-displayName: user1_dom1-19661
-uSNCreated: 2223663
-memberOf: cn=group1_dom1-19661,cn=Users,dc=example,dc=com
-uSNChanged: 2223667
-name: user1_dom1-19661
-objectGUID:: qyJVkvQrRUyig6rpPsXNUw==
-userAccountControl: 512
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 0
-pwdLastSet: 131079606172284326
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EeUMBAA==
-accountExpires: 0
-logonCount: 0
-sAMAccountName: user1_dom1-19661
-sAMAccountType: 805306368
-userPrincipalName: user1_dom1-19661@example.com
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-uid: user1_dom1-19661
-msSFU30Name: user1_dom1-19661
-
-dn: cn=group1_dom1-19661,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: group1_dom1-19661
-member: cn=user1_dom1-19661,cn=Users,dc=example,dc=com
-distinguishedName: cn=group1_dom1-19661,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20160517121017.0Z
-whenChanged: 20160517121018.0Z
-uSNCreated: 2223669
-uSNChanged: 2223673
-name: group1_dom1-19661
-objectGUID:: 8BulXIrOCkmlc6HgV+PAvw==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EekMBAA==
-sAMAccountName: group1_dom1-19661
-sAMAccountType: 268435456
-groupType: -2147483640
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=user2_dom1-19661,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: user2_dom1-19661
-givenName: user2_dom1-19661
-distinguishedName: cn=user2_dom1-19661,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20160517121018.0Z
-whenChanged: 20160517121019.0Z
-displayName: user2_dom1-19661
-uSNCreated: 2223676
-memberOf: cn=group2_dom2-19661,cn=Users,dc=example_tree,dc=com
-uSNChanged: 2223680
-name: user2_dom1-19661
-objectGUID:: YSnhUKGpFUC+SqxUvvXugA==
-userAccountControl: 512
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 0
-pwdLastSet: 131079606188221826
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8Ee0MBAA==
-accountExpires: 0
-logonCount: 0
-sAMAccountName: user2_dom1-19661
-sAMAccountType: 805306368
-userPrincipalName: user2_dom1-19661@example.com
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-uid: user2_dom1-19661
-msSFU30Name: user2_dom1-19661
-
-dn: cn=group3_dom1-19661,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: group3_dom1-19661
-member: cn=user3_dom3-19661,cn=Users,dc=child1,dc=example,dc=com
-distinguishedName: cn=group3_dom1-19661,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20160517121145.0Z
-whenChanged: 20160517121146.0Z
-uSNCreated: 2223750
-uSNChanged: 2223754
-name: group3_dom1-19661
-objectGUID:: 7bIPzON/JEKmGsVlRmhU3g==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EfEMBAA==
-sAMAccountName: group3_dom1-19661
-sAMAccountType: 268435456
-groupType: -2147483640
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=TelnetClients,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: TelnetClients
-distinguishedName: cn=TelnetClients,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923184913.0Z
-whenChanged: 20140923184913.0Z
-uSNCreated: 12704
-uSNChanged: 12706
-name: TelnetClients
-objectGUID:: pen22ZTevU2Rb+8+krexQA==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ETwQAAA==
-sAMAccountName: TelnetClients
-sAMAccountType: 536870912
-groupType: -2147483644
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=SSSDAD_TREE$,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: SSSDAD_TREE$
-distinguishedName: cn=SSSDAD_TREE$,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20141002150546.0Z
-whenChanged: 20160504032042.0Z
-uSNCreated: 31148
-uSNChanged: 2196300
-name: SSSDAD_TREE$
-objectGUID:: SYm5qEjtH0SySg5aQw6XNA==
-userAccountControl: 2080
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 0
-pwdLastSet: 131068056421414345
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8EUQQAAA==
-accountExpires: 9223372036854775807
-logonCount: 0
-sAMAccountName: SSSDAD_TREE$
-sAMAccountType: 805306370
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=user1_dom1-17775,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: user1_dom1-17775
-givenName: user1_dom1-17775
-distinguishedName: cn=user1_dom1-17775,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20160517104141.0Z
-whenChanged: 20160517105245.0Z
-displayName: user1_dom1-17775
-uSNCreated: 2220148
-memberOf: cn=group1_dom1-17775,cn=Users,dc=example,dc=com
-uSNChanged: 2220869
-name: user1_dom1-17775
-objectGUID:: dCwgefPZTEaA5Gq7fuH9eQ==
-userAccountControl: 512
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 131079562057827406
-pwdLastSet: 131079557906733656
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ESUMBAA==
-accountExpires: 0
-logonCount: 46
-sAMAccountName: user1_dom1-17775
-sAMAccountType: 805306368
-userPrincipalName: user1_dom1-17775@example.com
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-lastLogonTimestamp: 131079557817046156
-uid: user1_dom1-17775
-msSFU30Name: user1_dom1-17775
-
-dn: cn=group1_dom1-17775,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: group1_dom1-17775
-member: cn=user1_dom1-17775,cn=Users,dc=example,dc=com
-distinguishedName: cn=group1_dom1-17775,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20160517104143.0Z
-whenChanged: 20160517104143.0Z
-uSNCreated: 2220154
-uSNChanged: 2220158
-name: group1_dom1-17775
-objectGUID:: UfJpBGL6gE2d5hqzqNlRGQ==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ESkMBAA==
-sAMAccountName: group1_dom1-17775
-sAMAccountType: 268435456
-groupType: -2147483640
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=user2_dom1-17775,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: user2_dom1-17775
-givenName: user2_dom1-17775
-distinguishedName: cn=user2_dom1-17775,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20160517104143.0Z
-whenChanged: 20160517105302.0Z
-displayName: user2_dom1-17775
-uSNCreated: 2220161
-memberOf: cn=group2_dom2-17775,cn=Users,dc=example_tree,dc=com
-uSNChanged: 2220886
-name: user2_dom1-17775
-objectGUID:: r22lHyI8Y0eMVzeTH2dzoQ==
-userAccountControl: 512
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 131079561237671156
-pwdLastSet: 131079553041264906
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ES0MBAA==
-accountExpires: 0
-logonCount: 14
-sAMAccountName: user2_dom1-17775
-sAMAccountType: 805306368
-userPrincipalName: user2_dom1-17775@example.com
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-lastLogonTimestamp: 131079559824702406
-uid: user2_dom1-17775
-msSFU30Name: user2_dom1-17775
-
-dn: cn=group3_dom1-17775,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: group
-cn: group3_dom1-17775
-member: cn=user3_dom3-17775,cn=Users,dc=child1,dc=example,dc=com
-distinguishedName: cn=group3_dom1-17775,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20160517104312.0Z
-whenChanged: 20160517104312.0Z
-uSNCreated: 2220239
-uSNChanged: 2220243
-name: group3_dom1-17775
-objectGUID:: jkkwGJCVb0K4OCjHZVDmdQ==
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8ETEMBAA==
-sAMAccountName: group3_dom1-17775
-sAMAccountType: 268435456
-groupType: -2147483640
-objectCategory: cn=Group,cn=Schema,cn=Configuration,dc=example,dc=com
-dSCorePropagationData: 16010101000000.0Z
-
-dn: cn=Administrator,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: Administrator
-description: Built-in account for administering the computer/domain
-distinguishedName: cn=Administrator,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923233931.0Z
-whenChanged: 20160510092815.0Z
-uSNCreated: 8196
-memberOf: cn=Group Policy Creator Owners,cn=Users,dc=example,dc=com
-memberOf: cn=Domain Admins,cn=Users,dc=example,dc=com
-memberOf: cn=Enterprise Admins,cn=Users,dc=example,dc=com
-memberOf: cn=Schema Admins,cn=Users,dc=example,dc=com
-memberOf: cn=Administrators,cn=Builtin,dc=example,dc=com
-uSNChanged: 2204950
-name: Administrator
-objectGUID:: QeHMqu/QPEyjJ+KQEqcKFw==
-userAccountControl: 66048
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 131074379403763791
-lastLogoff: 0
-lastLogon: 131079606125409326
-logonHours:: ////////////////////////////
-pwdLastSet: 130553133586093750
-primaryGroupID: 513
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8E9AEAAA==
-adminCount: 1
-accountExpires: 0
-logonCount: 7477
-sAMAccountName: Administrator
-sAMAccountType: 805306368
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 20140923185530.0Z
-dSCorePropagationData: 16010101000000.0Z
-lastLogonTimestamp: 131073460951421705
-
-dn: cn=Guest,cn=Users,dc=example,dc=com
-objectClass: top
-objectClass: person
-objectClass: organizationalPerson
-objectClass: user
-cn: Guest
-description: Built-in account for guest access to the computer/domain
-distinguishedName: cn=Guest,cn=Users,dc=example,dc=com
-instanceType: 4
-whenCreated: 20140923233931.0Z
-whenChanged: 20140923233931.0Z
-uSNCreated: 8197
-memberOf: cn=Guests,cn=Builtin,dc=example,dc=com
-uSNChanged: 8197
-name: Guest
-objectGUID:: pZVy9Q6Eh02XuYDEXDE9Cg==
-userAccountControl: 66082
-badPwdCount: 0
-codePage: 0
-countryCode: 0
-badPasswordTime: 0
-lastLogoff: 0
-lastLogon: 0
-pwdLastSet: 0
-primaryGroupID: 514
-objectSid:: AQUAAAAAAAUVAAAADcfLTVzC66zo0l8E9QEAAA==
-accountExpires: 9223372036854775807
-logonCount: 0
-sAMAccountName: Guest
-sAMAccountType: 805306368
-objectCategory: cn=Person,cn=Schema,cn=Configuration,dc=example,dc=com
-isCriticalSystemObject: TRUE
-dSCorePropagationData: 16010101000000.0Z
diff --git a/src/tests/intg/data/ad_schema.ldif b/src/tests/intg/data/ad_schema.ldif
deleted file mode 100644
index 6ae533a55fa..00000000000
--- a/src/tests/intg/data/ad_schema.ldif
+++ /dev/null
@@ -1,42 +0,0 @@
-dn: cn=ad,cn=schema,cn=config
-objectClass: olcSchemaConfig
-cn: ad
-structuralObjectClass: olcSchemaConfig
-olcAttributeTypes: {0}( 1.2.840.113556.1.4.750 NAME 'groupType' SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {1}( 1.2.840.113556.1.4.221 NAME 'sAMAccountName' EQUALITY caseIgnoreMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {2}( 1.2.840.113556.1.4.35 NAME 'employeeID' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {3}( 1.2.840.113556.1.2.1 NAME 'instanceType' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {4}( 1.2.840.113556.1.4.782 NAME 'objectCategory' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {5}( 1.2.840.113556.1.2.2 NAME 'whenCreated' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {6}( 1.2.840.113556.1.2.3 NAME 'whenChanged' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {7}( 1.2.840.113556.1.2.19 NAME 'uSNCreated' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {8}( 1.2.840.113556.1.2.120 NAME 'uSNChanged' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {9}( 1.2.840.113556.1.2.169 NAME 'showInAdvancedViewOnly' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
-olcAttributeTypes: {10}( 1.2.840.113556.1.4.2 NAME 'objectGUID' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE)
-olcAttributeTypes: {11}( 1.2.840.113556.1.4.375 NAME 'systemFlags' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {12}( 1.2.840.113556.1.4.868 NAME 'isCriticalSystemObject' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
-olcAttributeTypes: {13}( 1.2.840.113556.1.4.1357 NAME 'dSCorePropagationData' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )
-olcAttributeTypes: {14}( 1.2.840.113556.1.4.8 NAME 'userAccountControl' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {15}( 1.2.840.113556.1.4.12 NAME 'badPwdCount' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {16}( 1.2.840.113556.1.4.146 NAME 'objectSid' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE)
-olcAttributeTypes: {17}( 1.2.840.113556.1.2.102 NAME 'memberOf' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
-olcAttributeTypes: {18}( 1.2.840.113556.1.4.16 NAME 'codePage' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {19}( 1.2.840.113556.1.4.302 NAME 'sAMAccountType' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {20}( 1.2.840.113556.1.4.150 NAME 'adminCount' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {21}( 1.2.840.113556.1.4.25 NAME 'countryCode' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {22}( 1.2.840.113556.1.4.49 NAME 'badPasswordTime' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {23}( 1.2.840.113556.1.6.18.1.339 NAME 'msSFU30NisDomain' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {24}( 1.2.840.113556.1.4.51 NAME 'lastLogoff' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {25}( 1.2.840.113556.1.4.52 NAME 'lastLogon' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {26}( 1.2.840.113556.1.4.96 NAME 'pwdLastSet' EQUALITY numericStringMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.36' SINGLE-VALUE )
-olcAttributeTypes: {27}( 1.2.840.113556.1.4.64 NAME 'logonHours' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE)
-olcAttributeTypes: {28}( 1.2.840.113556.1.4.98 NAME 'primaryGroupID' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {29}( 1.2.840.113556.1.4.159 NAME 'accountExpires' EQUALITY numericStringMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.36' SINGLE-VALUE )
-olcAttributeTypes: {30}( 1.2.840.113556.1.4.169 NAME 'logonCount' EQUALITY integerMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.27' SINGLE-VALUE )
-olcAttributeTypes: {31}( 1.2.840.113556.1.4.771 NAME 'servicePrincipalName' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {31}( 1.2.840.113556.1.4.656 NAME 'userPrincipalName' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {32}( 1.2.840.113556.1.6.18.1.309 NAME 'msSFU30Name' EQUALITY caseExactMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )
-olcAttributeTypes: {33}( 1.2.840.113556.1.4.1696 NAME 'lastLogonTimestamp' EQUALITY numericStringMatch SYNTAX '1.3.6.1.4.1.1466.115.121.1.36' SINGLE-VALUE )
-olcObjectClasses: {1}( 1.2.840.113556.1.5.9 NAME 'user' DESC 'a user' SUP organizationalPerson STRUCTURAL MUST ( cn $ objectSid $ instanceType $ sAMAccountName $ objectCategory ) MAY ( userPassword $ description $ distinguishedName $ name $ userAccountControl $ badPwdCount $ memberOf $ codePage $ sAMAccountType $ adminCount $ countryCode $ dSCorePropagationData $ whenCreated $ whenChanged $ uSNCreated $ uSNChanged $ badPasswordTime $ msSFU30NisDomain $ lastLogoff $ lastLogon $ objectGUID $ pwdLastSet $ logonCount $ logonHours $ primaryGroupID $ accountExpires $ isCriticalSystemObject $ servicePrincipalName $ userPrincipalName $ msSFU30Name $ lastLogonTimestamp $ showInAdvancedViewOnly $ givenName $ displayName $ uid ) )
-olcObjectClasses: {2}( 1.2.840.113556.1.5.8 NAME 'group' DESC 'a group of users' SUP top STRUCTURAL MUST ( groupType $ cn $ objectSid $ instanceType $ sAMAccountName $ objectCategory ) MAY ( member $ description $ distinguishedName $ name $ memberOf $ sAMAccountType $ adminCount $ dSCorePropagationData $ whenCreated $ whenChanged $ uSNCreated $ uSNChanged $ msSFU30NisDomain $ objectGUID $ isCriticalSystemObject $ gidNumber ) )
-olcObjectClasses: {3}( 1.2.840.113556.1.3.23 NAME 'container' DESC 'asdasd' SUP top STRUCTURAL MUST ( cn $ instanceType $ objectCategory ) MAY ( whenCreated $ whenChanged $ uSNCreated $ uSNChanged $ showInAdvancedViewOnly $ objectGUID $ systemFlags $ isCriticalSystemObject $ dSCorePropagationData $ description $ distinguishedName $ name ) )
diff --git a/src/tests/intg/data/cert_schema.ldif b/src/tests/intg/data/cert_schema.ldif
deleted file mode 100644
index 0003c662326..00000000000
--- a/src/tests/intg/data/cert_schema.ldif
+++ /dev/null
@@ -1,11 +0,0 @@
-dn: cn=cert,cn=schema,cn=config
-objectClass: olcSchemaConfig
-cn: cert
-olcAttributeTypes: ( 1.2.840.113556.1.4.645 NAME 'userCert'
- DESC 'MANDATORY: X.509 user certificate'
- EQUALITY octetStringMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
-olcObjectClasses: ( 1.2.840.113556.1.3.46 NAME 'mailRecipient' SUP top AUXILIARY
- DESC 'MANDATORY: X.509 objectclass'
- MAY ( userCert $ uid )
- )
diff --git a/src/tests/intg/data/cwrap-dbus-system.conf.in b/src/tests/intg/data/cwrap-dbus-system.conf.in
deleted file mode 100644
index 7369054e717..00000000000
--- a/src/tests/intg/data/cwrap-dbus-system.conf.in
+++ /dev/null
@@ -1,83 +0,0 @@
-
-
-
-
-
-
-
-
- system
-
-
-
-
-
-
-
-
-
-
- @dbusservicedir@
-
-
-
- @runstatedir@/dbus/messagebus.pid
-
-
- EXTERNAL
-
-
- unix:path=@runstatedir@/dbus/system_bus_socket
-
-
-
-
-
-
-
-
-
-
- system.d
-
-
-
-
- /etc/dbus-1/system-local.conf
-
- contexts/dbus_contexts
-
-
-
-
-
-
-
diff --git a/src/tests/intg/data/ssh_schema.ldif b/src/tests/intg/data/ssh_schema.ldif
deleted file mode 100644
index efe05706b9d..00000000000
--- a/src/tests/intg/data/ssh_schema.ldif
+++ /dev/null
@@ -1,11 +0,0 @@
-dn: cn=openssh-lpk,cn=schema,cn=config
-objectClass: olcSchemaConfig
-cn: openssh-lpk
-olcAttributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey'
- DESC 'MANDATORY: OpenSSH Public key'
- EQUALITY octetStringMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
-olcObjectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY
- DESC 'MANDATORY: OpenSSH LPK objectclass'
- MAY ( sshPublicKey $ uid )
- )
diff --git a/src/tests/intg/data/sudo_schema.ldif b/src/tests/intg/data/sudo_schema.ldif
deleted file mode 100644
index 8c1f4e3ef76..00000000000
--- a/src/tests/intg/data/sudo_schema.ldif
+++ /dev/null
@@ -1,11 +0,0 @@
-dn: cn=sudo,cn=schema,cn=config
-objectClass: olcSchemaConfig
-cn: sudo
-olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
-olcObjectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) )
diff --git a/src/tests/intg/ds.py b/src/tests/intg/ds.py
deleted file mode 100644
index f4631b28fd0..00000000000
--- a/src/tests/intg/ds.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#
-# Abstract directory server instance class
-#
-# Copyright (c) 2015 Red Hat, Inc.
-# Author: Nikolai Kondrashov
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import ldap
-
-
-class DS(object):
- """Abstract directory server instance."""
-
- def __init__(self, dir, port, base_dn, admin_rdn, admin_pw):
- """
- Initialize the instance.
-
- Arguments:
- dir Path to the root of the filesystem hierarchy to create
- the instance under.
- port TCP port on localhost to bind the server to.
- base_dn Base DN.
- admin_rdn Administrator DN, relative to BASE_DN.
- admin_pw Administrator password.
- """
- self.dir = dir
- self.port = port
- self.ldap_url = "ldap://localhost:" + str(self.port)
- self.base_dn = base_dn
- self.admin_rdn = admin_rdn
- self.admin_dn = admin_rdn + "," + base_dn
- self.admin_pw = admin_pw
-
- def setup(self):
- """Setup the instance"""
- raise NotImplementedError()
-
- def teardown(self):
- """Teardown the instance"""
- raise NotImplementedError()
-
- def bind(self):
- """Connect to the server and bind as admin, return connection."""
- conn = ldap.initialize(self.ldap_url)
- conn.simple_bind_s(self.admin_dn, self.admin_pw)
- return conn
diff --git a/src/tests/intg/ds_openldap.py b/src/tests/intg/ds_openldap.py
deleted file mode 100644
index 158134383aa..00000000000
--- a/src/tests/intg/ds_openldap.py
+++ /dev/null
@@ -1,398 +0,0 @@
-#
-# OpenLDAP directory server instance class
-#
-# Copyright (c) 2015 Red Hat, Inc.
-# Author: Nikolai Kondrashov
-# Author: Lukas Slebodnik
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import hashlib
-import base64
-import time
-import ldap
-import os
-import errno
-import signal
-import shutil
-import subprocess
-from util import unindent, first_dir
-from ds import DS
-
-try:
- from urllib import quote as url_quote
-except ImportError:
- from urllib.parse import quote as url_quote
-
-
-def hash_password(password):
- """Generate userPassword value for a password."""
- salt = os.urandom(4)
- hash = hashlib.sha1(password.encode('utf-8'))
- hash.update(salt)
- hash_base64 = base64.standard_b64encode(hash.digest() + salt)
- return "{SSHA}" + hash_base64.decode('utf-8')
-
-
-class DSOpenLDAP(DS):
- """OpenLDAP directory server instance."""
-
- def __init__(self, dir, port, base_dn, admin_rdn, admin_pw):
- """
- Initialize the instance.
-
- Arguments:
- dir Path to the root of the filesystem hierarchy to create
- the instance under.
- port TCP port on localhost to bind the server to.
- base_dn Base DN.
- admin_rdn Administrator DN, relative to BASE_DN.
- admin_pw Administrator password.
- """
- DS.__init__(self, dir, port, base_dn, admin_rdn, admin_pw)
- self.run_dir = self.dir + "/var/run/ldap"
- self.pid_path = self.run_dir + "/slapd.pid"
- self.conf_dir = self.dir + "/etc/ldap"
- self.conf_slapd_d_dir = self.conf_dir + "/slapd.d"
- self.data_dir = self.dir + "/var/lib/ldap"
-
- def _setup_config(self):
- """Setup the instance initial configuration."""
- dist_lib_dir = first_dir("/usr/lib64/openldap",
- "/usr/lib/openldap",
- "/usr/lib/ldap")
- dist_conf_dir = first_dir("/etc/ldap",
- "/etc/openldap")
- args_file = self.run_dir + "/slapd.args"
- admin_pw_hash = hash_password(self.admin_pw)
- uid = os.geteuid()
- gid = os.getegid()
-
- #
- # Add configuration
- #
- config = unindent("""
- dn: cn=config
- objectClass: olcGlobal
- cn: config
- olcPidFile: {self.pid_path}
- olcArgsFile: {args_file}
- # Read slapd.conf(5) for possible values
- olcLogLevel: none
-
- # Frontend settings
- dn: olcDatabase={{-1}}frontend,cn=config
- objectClass: olcDatabaseConfig
- objectClass: olcFrontendConfig
- olcDatabase: {{-1}}frontend
- # The maximum number of entries that is returned for
- # a search operation
- olcSizeLimit: 500
- # Allow unlimited access to local connection from the local root
- olcAccess: {{0}}to * by dn.exact=gidNumber={gid}+uidNumber={uid},
- cn=peercred,cn=external,cn=auth manage by * break
- # Allow unauthenticated read access for schema and
- # base DN autodiscovery
- olcAccess: {{1}}to dn.exact="" by * read
- olcAccess: {{2}}to dn.base="cn=Subschema" by * read
-
- # Config db settings
- dn: olcDatabase=config,cn=config
- objectClass: olcDatabaseConfig
- olcDatabase: config
- # Allow unlimited access to local connection from the local root
- olcAccess: to * by dn.exact=gidNumber={gid}+uidNumber={uid},
- cn=peercred,cn=external,cn=auth manage by * break
- olcRootDN: {self.admin_rdn},cn=config
- olcRootPW: {admin_pw_hash}
-
- # Load schemas
- dn: cn=schema,cn=config
- objectClass: olcSchemaConfig
- cn: schema
-
- include: file://{dist_conf_dir}/schema/core.ldif
- include: file://{dist_conf_dir}/schema/cosine.ldif
- include: file://{dist_conf_dir}/schema/nis.ldif
- include: file://{dist_conf_dir}/schema/inetorgperson.ldif
-
- # Load module
- dn: cn=module{{0}},cn=config
- objectClass: olcModuleList
- cn: module{{0}}
- olcModulePath: {dist_lib_dir}
- olcModuleLoad: back_mdb
-
- # Set defaults for the backend
- dn: olcBackend=mdb,cn=config
- objectClass: olcBackendConfig
- olcBackend: mdb
-
- # The database definition.
- dn: olcDatabase=mdb,cn=config
- objectClass: olcDatabaseConfig
- objectClass: olcMdbConfig
- olcDatabase: mdb
- olcDbCheckpoint: 512 30
- olcLastMod: TRUE
- olcSuffix: {self.base_dn}
- olcDbDirectory: {self.data_dir}
- olcRootDN: {self.admin_dn}
- olcRootPW: {admin_pw_hash}
- olcDbIndex: objectClass eq
- olcDbIndex: cn,uid eq
- olcDbIndex: uidNumber,gidNumber eq
- olcDbIndex: member,memberUid eq
- olcAccess: to attrs=userPassword,shadowLastChange
- by self write
- by anonymous auth
- by * none
- olcAccess: to dn.base="" by * read
- olcAccess: to *
- by * read
- """).format(**locals())
-
- slapadd = subprocess.Popen(
- ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config"],
- stdin=subprocess.PIPE, close_fds=True
- )
- slapadd.communicate(config.encode('utf-8'))
- if slapadd.returncode != 0:
- raise Exception("Failed to add configuration with slapadd")
-
- #
- # Add database config (example from distribution)
- #
- db_config = unindent("""
- # One 0.25 GB cache
- set_cachesize 0 268435456 1
-
- # Transaction Log settings
- set_lg_regionmax 262144
- set_lg_bsize 2097152
- """)
- db_config_file = open(self.data_dir + "/DB_CONFIG", "w")
- db_config_file.write(db_config)
- db_config_file.close()
-
- # Import ad schema
- subprocess.check_call(
- ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config",
- "-l", "data/ssh_schema.ldif"],
- )
-
- # Import sudo schema
- subprocess.check_call(
- ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config",
- "-l", "data/sudo_schema.ldif"],
- )
-
- # Import cert schema
- subprocess.check_call(
- ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config",
- "-l", "data/cert_schema.ldif"],
- )
-
- def _start_daemon(self):
- """Start the instance."""
- if subprocess.call(["slapd", "-F", self.conf_slapd_d_dir,
- "-h", self.url_list]) != 0:
- raise Exception("Failed to start slapd")
-
- #
- # Wait until it is available
- #
- attempt = 0
- while True:
- try:
- ldap_conn = ldap.initialize(self.ldapi_url)
- ldap_conn.simple_bind_s(self.admin_rdn + ",cn=config",
- self.admin_pw)
- ldap_conn.unbind_s()
- ldap_conn = ldap.initialize(self.ldap_url)
- ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
- ldap_conn.unbind_s()
- break
- except ldap.SERVER_DOWN:
- pass
- attempt = attempt + 1
- if attempt > 30:
- raise Exception("Failed to start slapd")
- time.sleep(1)
-
- def setup(self):
- """Setup the instance."""
- ldapi_socket = self.run_dir + "/ldapi"
- self.ldapi_url = "ldapi://" + url_quote(ldapi_socket, "")
- self.url_list = self.ldapi_url + " " + self.ldap_url
-
- os.makedirs(self.conf_slapd_d_dir)
- os.makedirs(self.run_dir)
- os.makedirs(self.data_dir)
-
- #
- # Setup initial configuration
- #
- self._setup_config()
-
- self._start_daemon()
-
- #
- # Relax requirement of member attribute presence in groupOfNames
- #
- modlist = [
- (ldap.MOD_DELETE, "olcObjectClasses",
- b"{7}( 2.5.6.9 NAME 'groupOfNames' "
- b"DESC 'RFC2256: a group of names (DNs)' SUP top "
- b"STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $ "
- b"seeAlso $ owner $ ou $ o $ description ) )"),
- (ldap.MOD_ADD, "olcObjectClasses",
- b"{7}( 2.5.6.9 NAME 'groupOfNames' "
- b"DESC 'RFC2256: a group of names (DNs)' SUP top "
- b"STRUCTURAL MUST ( cn ) MAY ( member $ businessCategory $ "
- b"seeAlso $ owner $ ou $ o $ description ) )"),
- ]
- ldap_conn = ldap.initialize(self.ldapi_url)
- ldap_conn.simple_bind_s(self.admin_rdn + ",cn=config", self.admin_pw)
- ldap_conn.modify_s("cn={0}core,cn=schema,cn=config", modlist)
- ldap_conn.unbind_s()
-
- #
- # Add data
- #
- ldap_conn = ldap.initialize(self.ldap_url)
- ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
- ldap_conn.add_s(self.base_dn, [
- ("objectClass", [b"dcObject", b"organization"]),
- ("o", b"Example Company"),
- ])
- ldap_conn.add_s("cn=Manager," + self.base_dn, [
- ("objectClass", b"organizationalRole"),
- ])
- for ou in ("Users", "Groups", "Netgroups", "Services", "Policies",
- "Hosts", "Networks"):
- ldap_conn.add_s("ou=" + ou + "," + self.base_dn, [
- ("objectClass", [b"top", b"organizationalUnit"]),
- ])
- ldap_conn.add_s("ou=sudoers," + self.base_dn, [
- ("objectClass", [b"top", b"organizationalUnit"]),
- ])
- ldap_conn.add_s("cn=testrule,ou=sudoers," + self.base_dn, [
- ("objectClass", [b"top", b"sudoRole"]),
- ("sudoUser", [b"tuser"]),
- ])
- ldap_conn.unbind_s()
-
- def _stop_daemon(self):
- """Stop the instance."""
- # Wait for slapd to stop
- try:
- pid_file = open(self.pid_path, "r")
- try:
- os.kill(int(pid_file.read()), signal.SIGTERM)
- finally:
- pid_file.close()
- attempt = 0
- while os.path.isfile(self.pid_path):
- attempt = attempt + 1
- if attempt > 30:
- raise Exception("Failed to stop slapd")
- time.sleep(1)
- except IOError as e:
- if e.errno != errno.ENOENT:
- raise
-
- def teardown(self):
- """Teardown the instance."""
- self._stop_daemon()
-
- for path in (self.conf_slapd_d_dir, self.run_dir, self.data_dir):
- shutil.rmtree(path, True)
-
-
-class FakeAD(DSOpenLDAP):
- """Fake Active Directory based on OpenLDAP directory server."""
-
- def _setup_config(self):
- """Setup the instance initial configuration."""
-
- # Import ad schema
- subprocess.check_call(
- ["slapadd", "-F", self.conf_slapd_d_dir, "-b", "cn=config",
- "-l", "data/ad_schema.ldif"],
- )
-
- def setup(self):
- """Setup the instance."""
- ldapi_socket = self.run_dir + "/ldapi"
- self.ldapi_url = "ldapi://" + url_quote(ldapi_socket, "")
- self.url_list = self.ldapi_url + " " + self.ldap_url
-
- os.makedirs(self.conf_slapd_d_dir)
- os.makedirs(self.run_dir)
- os.makedirs(self.data_dir)
-
- super(FakeAD, self)._setup_config()
- self._setup_config()
-
- # Start the daemon
- super(FakeAD, self)._start_daemon()
-
- # Relax requirement of surname attribute presence in person
- modlist = [
- (ldap.MOD_DELETE, "olcObjectClasses",
- b"{4}( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top "
- b"STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ "
- b"telephoneNumber $ seeAlso $ description ) )"),
- (ldap.MOD_ADD, "olcObjectClasses",
- b"{4}( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top "
- b"STRUCTURAL MUST ( cn ) MAY ( sn $ userPassword $ "
- b"telephoneNumber $ seeAlso $ description ) )"),
- ]
- ldap_conn = ldap.initialize(self.ldapi_url)
- ldap_conn.simple_bind_s(self.admin_rdn + ",cn=config", self.admin_pw)
- ldap_conn.modify_s("cn={0}core,cn=schema,cn=config", modlist)
- ldap_conn.unbind_s()
-
- # restart daemon for reloading schema
- super(FakeAD, self)._stop_daemon()
- super(FakeAD, self)._start_daemon()
-
- # Add data
- ldap_conn = ldap.initialize(self.ldap_url)
- ldap_conn.simple_bind_s(self.admin_dn, self.admin_pw)
- ldap_conn.add_s(self.base_dn, [
- ("objectClass", [b"dcObject", b"organization"]),
- ("o", b"Example Company"),
- ])
- ldap_conn.add_s("cn=Manager," + self.base_dn, [
- ("objectClass", b"organizationalRole"),
- ])
- for ou in ("Users", "Groups", "Netgroups", "Services", "Policies"):
- ldap_conn.add_s("ou=" + ou + "," + self.base_dn, [
- ("objectClass", [b"top", b"organizationalUnit"]),
- ])
- ldap_conn.unbind_s()
-
- # import data from real AD
- subprocess.check_call(
- ["ldapadd", "-x", "-w", self.admin_pw, "-D",
- self.admin_dn, "-H", self.ldap_url,
- "-f", "data/ad_data.ldif"],
- )
-
- def teardown(self):
- """Teardown the instance."""
- super(FakeAD, self).teardown()
diff --git a/src/tests/intg/ent.py b/src/tests/intg/ent.py
deleted file mode 100644
index d716ae5e656..00000000000
--- a/src/tests/intg/ent.py
+++ /dev/null
@@ -1,506 +0,0 @@
-#
-# Abstract passwd/group entry management
-#
-# Copyright (c) 2015 Red Hat, Inc.
-# Author: Nikolai Kondrashov
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-from pprint import pformat
-import pwd
-import grp
-
-_PASSWD_LIST_DESC = {None: ("user", {})}
-_GROUP_DESC = {"mem": ("member list", {None: ("member", {})})}
-_GROUP_LIST_DESC = {None: ("group", _GROUP_DESC)}
-
-
-def _get_desc(desc_map, key):
- """
- Get an item description from a container description map.
-
- Arguments:
- desc_map Container description map.
- key Item key, None for wildcard description.
- """
- assert isinstance(desc_map, dict)
- if key in desc_map:
- return desc_map[key]
- if None in desc_map:
- desc = desc_map[None]
- if key is not None:
- desc = (desc[0] + " " + pformat(key), desc[1])
- return desc
- elif key is None:
- return ("item", {})
- else:
- return (pformat(key), {})
-
-
-def _diff(ent, pattern, desc_map={}):
- """
- Describe difference between an entry and a pattern.
- Return None, if none.
-
- Arguments:
- ent Entry.
- pattern Pattern.
- desc_map Container pattern description map.
-
- An entry is a value, a list of entries, or a dictionary of entries.
- Entries are used to store passwd and group database entries as
- dictionaries, in lists and dictionaries.
-
- A pattern is a value, a tuple, a list, or a dictionary of patterns.
-
- E.g. 123, "abc", [ 123, "abc" ], { "abc": 123 }, { "abc": ( 123 ) }
-
- A pattern can be matched against a value, a list, or a dictionary entry.
-
- A value is considered matching, if it's equal to the pattern.
-
- E.g. 123 == 123, 123 != 456, "abc" == "abc", "abc" != "def", 123 != "abc"
-
- A list is considered matching a pattern, if the pattern is a list or a
- tuple, where each of pattern list items matches an entry list item and
- vice versa, or where each pattern tuple item matches an entry list item,
- but not necessarily the other way around.
-
- E.g. [] != "abc", [] == [], [ "abc", 123 ] == [ 123, "abc" ],
- [ "abc" ] != [ 123 ], [ 123 ] != [],
- [] == (), [ "abc", 123 ] == ( 123, "abc" ),
- [ "abc" ] != ( 123 ), [ 123 ] == (), [ 123, "abc" ] == ( 123 )
-
- NOTE: For the sake of readability, it is recommended to use
- "contains_only" function to create patterns matching all entry list
- items (list patterns), and "contains" function to create patterns
- matching a subset of entry list items (tuple patterns).
-
- A dictionary is considered matching a pattern, if it is also a dictionary,
- and all of pattern values match identically-keyed values of the
- dictionary.
-
- E.g. {} == {}, {} != "abc", { "abc": 123, "def": 456 } == { "abc": 123 },
- { "abc": 123 } == {}
-
- Container pattern description map is a dictionary with keys being item
- keys/indices and values being (name, description map) tuples. None key
- points to a wildcard description, others to specific item descriptions.
- The description map argument is optional, and is used to generate more
- readable difference explanations.
- """
- assert isinstance(desc_map, dict)
-
- if isinstance(pattern, dict):
- if not isinstance(ent, dict):
- return "not a dict, " + str(type(ent))
-
- for key, value in pattern.items():
- item_name, item_map = _get_desc(desc_map, key)
- d = _diff(ent[key], value, item_map)
- if d:
- return item_name + " mismatch: " + d
- elif isinstance(pattern, tuple):
- if not isinstance(ent, list):
- return "not a list, " + str(type(ent))
-
- pattern_matches = [0 for pv in pattern]
-
- for ei, ev in enumerate(ent):
- for pi, pv in enumerate(pattern):
- d = _diff(ev, pv)
- if not d:
- pattern_matches[pi] += 1
-
- unmatched_pattern = [pattern[pi] for pi in range(0, len(pattern))
- if pattern_matches[pi] == 0]
-
- items = _get_desc(desc_map, None)[0] + "s"
- if len(unmatched_pattern) > 0:
- return "\nexpected " + items + " not found:\n" + \
- pformat(unmatched_pattern)
- elif isinstance(pattern, list):
- if not isinstance(ent, list):
- return "not a list, " + str(type(ent))
-
- pattern_matches = [0 for pv in pattern]
- ent_matches = [0 for ev in ent]
-
- for ei, ev in enumerate(ent):
- for pi, pv in enumerate(pattern):
- d = _diff(ev, pv)
- if not d:
- pattern_matches[pi] += 1
- ent_matches[ei] += 1
-
- unmatched_pattern = [pattern[pi] for pi in range(0, len(pattern))
- if pattern_matches[pi] == 0]
- unmatched_ent = [ent[pi] for pi in range(0, len(ent))
- if ent_matches[pi] == 0]
-
- items = _get_desc(desc_map, None)[0] + "s"
- d = ""
- if len(unmatched_pattern) > 0:
- d += "\nexpected " + items + " not found:\n" + \
- pformat(unmatched_pattern)
- if len(unmatched_ent) != 0:
- d += "\nunexpected " + items + " found:\n" + \
- pformat(unmatched_ent)
- if len(d) > 0:
- return d
- else:
- if pattern != ent:
- return pformat(pattern) + " != " + pformat(ent)
-
- return None
-
-
-def contains_only(*args):
- """
- Produce a pattern matching all list items against arguments.
- Use this function instead of constructing bare lists, for readability.
- """
- return list(args)
-
-
-def contains(*args):
- """
- Produce a pattern matching a subset of list items against arguments.
- Use this function instead of constructing bare tuples, for readability.
- """
- return args
-
-
-def _convert_passwd(passwd):
- """
- Convert a passwd entry returned by pwd module to an entry dictionary.
- """
- return dict(
- name=passwd.pw_name,
- passwd=passwd.pw_passwd,
- uid=passwd.pw_uid,
- gid=passwd.pw_gid,
- gecos=passwd.pw_gecos,
- dir=passwd.pw_dir,
- shell=passwd.pw_shell
- )
-
-
-def get_passwd_by_name(name):
- """Get a passwd database entry by name."""
- return _convert_passwd(pwd.getpwnam(name))
-
-
-def get_passwd_by_uid(uid):
- """Get a passwd database entry by UID."""
- return _convert_passwd(pwd.getpwuid(uid))
-
-
-def assert_passwd_by_name(name, pattern):
- """Assert a passwd entry, retrieved by name, matches a pattern."""
- try:
- ent = get_passwd_by_name(name)
- except KeyError as err:
- assert False, err
- d = _diff(ent, pattern)
- assert not d, d
-
-
-def assert_passwd_by_uid(uid, pattern):
- """Assert a passwd entry, retrieved by UID, matches a pattern."""
- try:
- ent = get_passwd_by_uid(uid)
- except KeyError as err:
- assert False, err
- d = _diff(ent, pattern)
- assert not d, d
-
-
-def get_passwd_list():
- """Get passwd database entry list with root user removed."""
- passwd_list = pwd.getpwall()
- for i, v in enumerate(passwd_list):
- if v.pw_name == "root" and v.pw_uid == 0 and v.pw_gid == 0:
- del passwd_list[i]
- return list(map(_convert_passwd, passwd_list))
- raise Exception("no root user found")
-
-
-def assert_passwd_list(pattern):
- """Assert retrieved passwd list matches a pattern."""
- d = _diff(get_passwd_list(), pattern, _PASSWD_LIST_DESC)
- assert not d, d
-
-
-def _diff_each_passwd_by_name(pattern_dict):
- """
- Describe difference between each pattern_dict value and a passwd entry
- retrieved by name being the corresponding key.
- """
- try:
- ent = dict((k, get_passwd_by_name(k)) for k in pattern_dict.keys())
- except KeyError as err:
- return str(err)
- return _diff(ent, pattern_dict, _PASSWD_LIST_DESC)
-
-
-def _diff_each_passwd_by_uid(pattern_dict):
- """
- Describe difference between each pattern_dict value and a passwd entry
- retrieved by UID being the corresponding key.
- """
- try:
- ent = dict((k, get_passwd_by_uid(k)) for k in pattern_dict.keys())
- except KeyError as err:
- return str(err)
- return _diff(ent, pattern_dict, _PASSWD_LIST_DESC)
-
-
-def _diff_each_passwd_with_name(pattern_seq):
- """
- Describe difference between each pattern in pattern_seq sequence and a
- passwd entry retrieved by name being the pattern's "name" value.
- """
- return _diff_each_passwd_by_name(dict((p["name"], p) for p in pattern_seq))
-
-
-def _diff_each_passwd_with_uid(pattern_seq):
- """
- Describe difference between each pattern in pattern_seq sequence and a
- passwd entry retrieved by UID being the pattern's "uid" value.
- """
- return _diff_each_passwd_by_uid(dict((p["uid"], p) for p in pattern_seq))
-
-
-def assert_each_passwd_by_name(pattern_dict):
- """
- Assert each pattern_dict value matches a passwd entry retrieved by
- name being the corresponding key.
- """
- d = _diff_each_passwd_by_name(pattern_dict)
- assert not d, d
-
-
-def assert_each_passwd_by_uid(pattern_dict):
- """
- Assert each pattern_dict value matches a passwd entry retrieved by
- UID being the corresponding key.
- """
- d = _diff_each_passwd_by_uid(pattern_dict)
- assert not d, d
-
-
-def assert_each_passwd_with_name(pattern_seq):
- """
- Assert each pattern in pattern_seq sequence matches a passwd entry
- retrieved by name being the pattern's "name" value.
- """
- d = _diff_each_passwd_with_name(pattern_seq)
- assert not d, d
-
-
-def assert_each_passwd_with_uid(pattern_seq):
- """
- Assert each pattern in pattern_seq sequence matches a passwd entry
- retrieved by UID being the pattern's "uid" value.
- """
- d = _diff_each_passwd_with_uid(pattern_seq)
- assert not d, d
-
-
-def _diff_passwd(pattern):
- """
- Describe difference between passwd database and a pattern.
- Each pattern entry must have "name" and "uid" attribute.
- """
- d = _diff(get_passwd_list(), pattern, _PASSWD_LIST_DESC)
- if d:
- return "list mismatch: " + d
- d = _diff_each_passwd_with_name(pattern)
- if d:
- return "name retrieval mismatch: " + d
- d = _diff_each_passwd_with_uid(pattern)
- if d:
- return "UID retrieval mismatch: " + d
- return None
-
-
-def assert_passwd(pattern):
- """
- Assert passwd database matches a pattern.
- Each pattern entry must have "name" and "uid" attribute.
- """
- d = _diff_passwd(pattern)
- assert not d, d
-
-
-def _convert_group(group):
- """
- Convert a group entry returned by grp module to an entry dictionary.
- """
- return dict(
- name=group.gr_name,
- passwd=group.gr_passwd,
- gid=group.gr_gid,
- mem=group.gr_mem
- )
-
-
-def get_group_by_name(name):
- """Get a group database entry by name."""
- return _convert_group(grp.getgrnam(name))
-
-
-def get_group_by_gid(gid):
- """Get a group database entry by GID."""
- return _convert_group(grp.getgrgid(gid))
-
-
-def assert_group_by_name(name, pattern):
- """Assert a group entry, retrieved by name, matches a pattern."""
- try:
- ent = get_group_by_name(name)
- except KeyError as err:
- assert False, err
- d = _diff(ent, pattern, _GROUP_DESC)
- assert not d, d
-
-
-def assert_group_by_gid(gid, pattern):
- """Assert a group entry, retrieved by GID, matches a pattern."""
- try:
- ent = get_group_by_gid(gid)
- except KeyError as err:
- assert False, err
- d = _diff(ent, pattern, _GROUP_DESC)
- assert not d, d
-
-
-def get_group_list():
- """Get group database entry list with root group removed."""
- group_list = grp.getgrall()
- for i, v in enumerate(group_list):
- if v.gr_name == "root" and v.gr_gid == 0:
- del group_list[i]
- return list(map(_convert_group, group_list))
- raise Exception("no root group found")
-
-
-def assert_group_list(pattern):
- """Assert retrieved group list matches a pattern."""
- d = _diff(get_group_list(), pattern, _GROUP_LIST_DESC)
- assert not d, d
-
-
-def _diff_each_group_by_name(pattern_dict):
- """
- Describe difference between each pattern_dict value and a group entry
- retrieved by name being the corresponding key.
- """
- try:
- ent = dict((k, get_group_by_name(k)) for k in pattern_dict.keys())
- except KeyError as err:
- return str(err)
- return _diff(ent, pattern_dict, _GROUP_LIST_DESC)
-
-
-def _diff_each_group_by_gid(pattern_dict):
- """
- Describe difference between each pattern_dict value and a group entry
- retrieved by GID being the corresponding key.
- """
- try:
- ent = dict((k, get_group_by_gid(k)) for k in pattern_dict.keys())
- except KeyError as err:
- return str(err)
- return _diff(ent, pattern_dict, _GROUP_LIST_DESC)
-
-
-def _diff_each_group_with_name(pattern_seq):
- """
- Describe difference between each pattern in pattern_seq sequence and a
- group entry retrieved name being the pattern's "name" value.
- """
- return _diff_each_group_by_name(dict((p["name"], p) for p in pattern_seq))
-
-
-def _diff_each_group_with_gid(pattern_seq):
- """
- Describe difference between each pattern in pattern_seq sequence and a
- group entry retrieved by GID being the pattern's "gid" value.
- """
- return _diff_each_group_by_gid(dict((p["gid"], p) for p in pattern_seq))
-
-
-def assert_each_group_by_name(pattern_dict):
- """
- Assert each pattern_dict value matches a group entry retrieved by
- name being the corresponding key.
- """
- d = _diff_each_group_by_name(pattern_dict)
- assert not d, d
-
-
-def assert_each_group_by_gid(pattern_dict):
- """
- Assert each pattern_dict value matches a group entry retrieved by
- GID being the corresponding key.
- """
- d = _diff_each_group_by_gid(pattern_dict)
- assert not d, d
-
-
-def assert_each_group_with_name(pattern_seq):
- """
- Assert each pattern in pattern_seq sequence matches a group entry
- retrieved by name being the pattern's "name" value.
- """
- d = _diff_each_group_with_name(pattern_seq)
- assert not d, d
-
-
-def assert_each_group_with_gid(pattern_seq):
- """
- Assert each pattern in pattern_seq sequence matches a group entry
- retrieved by GID being the pattern's "gid" value.
- """
- d = _diff_each_group_with_gid(pattern_seq)
- assert not d, d
-
-
-def _diff_group(pattern):
- """
- Describe difference between group database and a pattern.
- Each pattern entry must have "name" and "gid" attribute.
- """
- d = _diff(get_group_list(), pattern, _GROUP_LIST_DESC)
- if d:
- return "list mismatch: " + d
- d = _diff_each_group_with_name(pattern)
- if d:
- return "name retrieval mismatch: " + d
- d = _diff_each_group_with_gid(pattern)
- if d:
- return "GID retrieval mismatch: " + d
- return None
-
-
-def assert_group(pattern):
- """
- Assert group database matches a pattern.
- Each pattern entry must have "name" and "gid" attribute.
- """
- d = _diff_group(pattern)
- assert not d, d
diff --git a/src/tests/intg/files_ops.py b/src/tests/intg/files_ops.py
deleted file mode 100644
index 57959f5010a..00000000000
--- a/src/tests/intg/files_ops.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#
-# SSSD integration test - operations on UNIX user and group database
-#
-# Copyright (c) 2016 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import os
-import os.path
-import tempfile
-import pytest
-
-import ent
-from util import backup_envvar_file, restore_envvar_file
-
-
-@pytest.fixture
-def passwd_ops_setup(request):
- pwd_file = os.environ["NSS_WRAPPER_PASSWD"]
- backup_envvar_file("NSS_WRAPPER_PASSWD")
- request.addfinalizer(lambda: restore_envvar_file("NSS_WRAPPER_PASSWD"))
- pwd_ops = PasswdOps(pwd_file)
- return pwd_ops
-
-
-@pytest.fixture
-def group_ops_setup(request):
- grp_file = os.environ["NSS_WRAPPER_GROUP"]
- backup_envvar_file("NSS_WRAPPER_GROUP")
- request.addfinalizer(lambda: restore_envvar_file("NSS_WRAPPER_GROUP"))
- grp_ops = GroupOps(grp_file)
- return grp_ops
-
-
-@pytest.fixture
-def group_db_setup(request):
- group = request.param
- grp_ops = group_ops_setup(request)
- grp_ops.groupadd(**group)
- ent.assert_group_by_name(group['name'], group)
- return grp_ops
-
-
-class FilesOps(object):
- """
- A naive implementation of operations as a basis for user or group
- operations. Uses rename to (hopefully) trigger the same fs-level
- notifications as shadow-utils would.
- """
- def __init__(self, file_name):
- self.file_name = file_name
- self.tmp_dir = os.path.dirname(self.file_name)
-
- @staticmethod
- def _get_named_line(name, contents):
- for num, line in enumerate(contents, 0):
- pname = line.split(':')[0]
- if name == pname:
- return num
- raise KeyError("%s not found" % name)
-
- def _read_contents(self):
- with open(self.file_name, "r") as pfile:
- contents = pfile.readlines()
- return contents
-
- def _write_contents(self, contents):
- tmp_file = tempfile.NamedTemporaryFile(mode='w', dir=self.tmp_dir,
- delete=False)
- tmp_file.writelines(contents)
- tmp_file.flush()
-
- os.rename(tmp_file.name, self.file_name)
-
- def _append_line(self, new_line):
- contents = self._read_contents()
- contents.extend(new_line)
- self._write_contents(contents)
-
- def _subst_line(self, key, line):
- contents = self._read_contents()
- kindex = self._get_named_line(key, contents)
- contents[kindex] = line
- self._write_contents(contents)
-
- def _del_line(self, key):
- contents = self._read_contents()
- kindex = self._get_named_line(key, contents)
- contents.pop(kindex)
- self._write_contents(contents)
-
- contents = self._read_contents()
-
- def _has_line(self, key):
- try:
- self._get_named_line(key, self._read_contents())
- return True
- except KeyError:
- return False
-
-
-class PasswdOps(FilesOps):
- """
- A naive implementation of user operations
- """
- def __init__(self, file_name):
- super(PasswdOps, self).__init__(file_name)
-
- def _pwd2line(self, name, uid, gid, passwd, gecos, homedir, shell):
- pwd_fmt = "{name}:{passwd}:{uid}:{gid}:{gecos}:{homedir}:{shell}\n"
- return pwd_fmt.format(name=name,
- passwd=passwd,
- uid=uid,
- gid=gid,
- gecos=gecos,
- homedir=homedir,
- shell=shell)
-
- def useradd(self, name, uid, gid, passwd='', gecos='', dir='', shell=''):
- pwd_line = self._pwd2line(name, uid, gid, passwd, gecos, dir, shell)
- self._append_line(pwd_line)
-
- def usermod(self, name, uid, gid, passwd='', gecos='', dir='', shell=''):
- pwd_line = self._pwd2line(name, uid, gid, passwd, gecos, dir, shell)
- self._subst_line(name, pwd_line)
-
- def userdel(self, name):
- self._del_line(name)
-
- def userexist(self, name):
- return self._has_line(name)
-
-
-class GroupOps(FilesOps):
- """
- A naive implementation of group operations
- """
- def __init__(self, file_name):
- super(GroupOps, self).__init__(file_name)
-
- def _grp2line(self, name, gid, mem, passwd):
- member_list = ",".join(m for m in mem)
- grp_fmt = "{name}:{passwd}:{gid}:{member_list}\n"
- return grp_fmt.format(name=name,
- passwd=passwd,
- gid=gid,
- member_list=member_list)
-
- def groupadd(self, name, gid, mem, passwd="*"):
- grp_line = self._grp2line(name, gid, mem, passwd)
- self._append_line(grp_line)
-
- def groupmod(self, old_name, name, gid, mem, passwd="*"):
- grp_line = self._grp2line(name, gid, mem, passwd)
- self._subst_line(old_name, grp_line)
-
- def groupdel(self, name):
- self._del_line(name)
-
- def groupexist(self, name):
- return self._has_line(name)
diff --git a/src/tests/intg/getsockopt_wrapper.c b/src/tests/intg/getsockopt_wrapper.c
deleted file mode 100644
index dc378d87a67..00000000000
--- a/src/tests/intg/getsockopt_wrapper.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* gcc -Wall -fPIC -shared -o getsockopt_wrapper.so getsockopt_wrapper.c -ldl */
-
-/* for RTLD_NEXT */
-#define _GNU_SOURCE 1
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-static bool is_dbus_socket(int fd)
-{
- int ret;
- struct sockaddr_storage addr = { 0 };
- socklen_t addrlen = sizeof(addr);
- struct sockaddr_un *unix_socket;
-
- ret = getsockname(fd, (struct sockaddr *)&addr, &addrlen);
- if (ret != 0) return false;
-
- if (addr.ss_family != AF_UNIX) return false;
-
- unix_socket = (struct sockaddr_un *)&addr;
-
- return NULL != strstr(unix_socket->sun_path, "system_bus_socket");
-}
-
-static bool peer_path_has(int fd, const char *str)
-{
- int ret;
- struct sockaddr_storage addr = { 0 };
- socklen_t addrlen = sizeof(addr);
- struct sockaddr_un *unix_socket;
-
- ret = getpeername(fd, (struct sockaddr *)&addr, &addrlen);
- if (ret != 0) return false;
-
- if (addr.ss_family != AF_UNIX) return false;
-
- unix_socket = (struct sockaddr_un *)&addr;
-
- return NULL != strstr(unix_socket->sun_path, str);
-}
-
-static bool peer_is(const struct ucred *cr, const char *str)
-{
- char proc_path[32];
- char cmd_line[255] = { 0 };
- int proc_fd;
- int ret;
-
- if (cr->pid < 0) {
- return false;
- }
-
- ret = snprintf(proc_path, sizeof(proc_path), "/proc/%d/cmdline",
- (int)cr->pid);
- if ((ret < 0) || (ret >= sizeof(proc_path))) {
- return false;
- }
-
- proc_fd = open(proc_path, O_RDONLY);
- if (proc_fd != -1) {
- ret = read(proc_fd, cmd_line, sizeof(cmd_line)-1);
- close(proc_fd);
- if (ret > 0) {
- cmd_line[ret] = 0;
- if (strstr(cmd_line, str) != NULL) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static void fake_peer_uid_gid(uid_t *uid, gid_t *gid)
-{
- char *val;
-
- val = getenv("SSSD_INTG_PEER_UID");
- if (val != NULL) {
- *uid = atoi(val);
- } else {
- *uid = -1;
- }
-
- val = getenv("SSSD_INTG_PEER_GID");
- if (val != NULL) {
- *gid = atoi(val);
- } else {
- *gid = -1;
- }
-}
-
-typedef typeof(getsockopt) getsockopt_fn_t;
-
-static getsockopt_fn_t *orig_getsockopt = NULL;
-
-int getsockopt(int sockfd, int level, int optname,
- void *optval, socklen_t *optlen)
-{
- int ret;
-#ifdef __OpenBSD__
- struct sockpeercred *cr;
-#else
- struct ucred *cr;
-#endif
-
- if (orig_getsockopt == NULL) {
- orig_getsockopt = (getsockopt_fn_t *)dlsym(RTLD_NEXT, "getsockopt");
- }
-
- ret = orig_getsockopt(sockfd, level, optname, optval, optlen);
-
- if (ret == 0 && level == SOL_SOCKET && optname == SO_PEERCRED
- && *optlen == sizeof(*cr)) {
- cr = optval;
- if (cr->uid != 0 && is_dbus_socket(sockfd)) {
- cr->uid = 0;
- } else if (peer_path_has(sockfd, "pipes/pam") ||
- peer_path_has(sockfd, "pipes/sudo") ||
- peer_is(cr, "sssctl") ||
- peer_is(cr, "sss_sudo_cli")) {
- fake_peer_uid_gid(&cr->uid, &cr->gid);
- }
- }
-
- return ret;
-}
diff --git a/src/tests/intg/kdc.py b/src/tests/intg/kdc.py
deleted file mode 100644
index a574e1f6775..00000000000
--- a/src/tests/intg/kdc.py
+++ /dev/null
@@ -1,178 +0,0 @@
-#
-# MIT Kerberos server class
-#
-# Copyright (c) 2016 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-import os
-import signal
-import shutil
-import subprocess
-
-from util import unindent
-
-
-class KDC(object):
- """
- MIT Kerberos KDC instance
- """
-
- def __init__(self, basedir, realm,
- includedir=None,
- kdc_port=10088,
- kadmin_port=10749,
- master_key='master'):
- self.basedir = basedir
- self.realm = realm
- self.kdc_port = kdc_port
- self.kadmin_port = kadmin_port
- self.master_key = master_key
-
- self.kdc_basedir = self.basedir + "/var/krb5kdc"
- self.includedir = includedir or (self.kdc_basedir + "/include")
- self.kdc_logdir = self.kdc_basedir + "/log"
- self.kdc_conf_path = self.kdc_basedir + "/kdc.conf"
- self.krb5_conf_path = self.kdc_basedir + "/krb5.conf"
-
- self.kdc_pid_file = self.kdc_basedir + "/kdc.pid"
-
- self.acl_file = self.kdc_basedir + "/kadm5.acl"
-
- self.admin_princ = "admin/admin@" + self.realm
-
- def start_kdc(self, extra_args=[]):
- args = ["krb5kdc", '-P', self.kdc_pid_file] + extra_args
- return self._run_in_env(args, self.get_krb5_env())
-
- def stop_kdc(self):
- try:
- with open(self.kdc_pid_file, "r") as pid_file:
- os.kill(int(pid_file.read()), signal.SIGTERM)
- except IOError as ioex:
- if ioex.errno == 2:
- pass
- else:
- raise ioex
-
- def teardown(self):
- self.stop_kdc()
- shutil.rmtree(self.kdc_basedir)
-
- def set_up(self):
- self._create_config()
- self._create_acl()
- self._create_kdb()
-
- def get_krb5_env(self):
- my_env = os.environ.copy()
- my_env['KRB5_CONFIG'] = self.krb5_conf_path
- my_env['KRB5_KDC_PROFILE'] = self.kdc_conf_path
- return my_env
-
- def add_config(self, include_files):
- for name, contents in include_files.items():
- include_fpath = os.path.join(self.includedir, name)
- with open(include_fpath, 'w') as include_file:
- include_file.write(contents)
-
- def add_principal(self, princ, password=None):
- args = ["kadmin.local", "-q"]
- if password is None:
- args += ["addprinc -randkey %s" % (princ)]
- else:
- args += ["addprinc -pw %s %s" % (password, princ)]
- return self._run_in_env(args, self.get_krb5_env())
-
- def _run_in_env(self, args, env):
- cmd = subprocess.Popen(args, env=env)
- out, err = cmd.communicate()
- return cmd.returncode, out, err
-
- def _create_config(self):
- try:
- os.makedirs(self.kdc_basedir)
- os.makedirs(self.kdc_logdir)
- os.makedirs(self.includedir)
- except OSError as osex:
- if osex.errno == 17:
- pass
-
- kdc_conf = self._format_kdc_conf()
- with open(self.kdc_conf_path, 'w') as kdc_conf_file:
- kdc_conf_file.write(kdc_conf)
-
- krb5_conf = self._format_krb5_conf()
- with open(self.krb5_conf_path, 'w') as krb5_conf_file:
- krb5_conf_file.write(krb5_conf)
-
- def _create_acl(self):
- with open(self.acl_file, 'w') as acl_fobject:
- acl_fobject.write(self.admin_princ)
-
- def _create_kdb(self):
- self._run_in_env(
- ['kdb5_util', 'create', '-W', '-s', '-P', self.master_key],
- self.get_krb5_env()
- )
-
- def _format_kdc_conf(self):
- database_path = self.kdc_basedir + "/principal"
- key_stash = self.kdc_basedir + "/stash." + self.realm
-
- kdc_logfile = "FILE:" + self.kdc_logdir + "/krb5kdc.log"
- kadmin_logfile = "FILE:" + self.kdc_logdir + "/kadmin.log"
- libkrb5_logfile = "FILE:" + self.kdc_logdir + "/libkrb5.log"
-
- kdc_conf = unindent("""
- [kdcdefaults]
- kdc_ports = {self.kdc_port}
- kdc_tcp_ports = {self.kdc_port}
-
- [realms]
- {self.realm} = {{
- kadmind_port = {self.kadmin_port}
- database_name = {database_path}
- key_stash_file = {key_stash}
- max_life = 7d
- max_renewable_life = 14d
- acl_file = {self.acl_file}
- }}
-
- [logging]
- kdc = {kdc_logfile}
- admin_server = {kadmin_logfile}
- default = {libkrb5_logfile}
- """).format(**locals())
- return kdc_conf
-
- def _format_krb5_conf(self):
- kdc_uri = "localhost:%d" % self.kdc_port
- kadmin_uri = "localhost:%d" % self.kadmin_port
-
- krb5_conf = unindent("""
- includedir {self.includedir}
-
- [libdefaults]
- default_realm = {self.realm}
- dns_lookup_kdc = false
- dns_lookup_realm = false
-
- [realms]
- {self.realm} = {{
- kdc = {kdc_uri}
- admin_server = {kadmin_uri}
- }}
- """).format(**locals())
- return krb5_conf
diff --git a/src/tests/intg/krb5utils.py b/src/tests/intg/krb5utils.py
deleted file mode 100644
index 2d1b79e7688..00000000000
--- a/src/tests/intg/krb5utils.py
+++ /dev/null
@@ -1,174 +0,0 @@
-#
-# MIT Kerberos server class
-#
-# Copyright (c) 2016 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-import os
-import subprocess
-
-
-class NoPrincipals(Exception):
- def __init__(self):
- Exception.__init__(self, 'No principals in the collection')
-
-
-class PrincNotFound(Exception):
- def __init__(self, principal):
- Exception.__init__(self, 'Principal %s not found' % principal)
-
-
-class Krb5Utils(object):
- """
- Helper class to test Kerberos command line utilities
- """
- def __init__(self, krb5_conf_path):
- self.krb5_conf_path = krb5_conf_path
-
- def spawn_in_env(self, args, stdin=None, extra_env=None):
- my_env = os.environ.copy()
- my_env['KRB5_CONFIG'] = self.krb5_conf_path
-
- if 'KRB5CCNAME' in my_env:
- del my_env['KRB5CCNAME']
- if extra_env is not None:
- my_env.update(extra_env)
-
- cmd = subprocess.Popen(args,
- env=my_env,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- return cmd
-
- def _run_in_env(self, args, stdin=None, extra_env=None):
- cmd = self.spawn_in_env(args, stdin, extra_env)
- out, err = cmd.communicate(stdin)
- return cmd.returncode, out.decode('utf-8'), err.decode('utf-8')
-
- def kinit(self, principal, password, options=None, env=None):
- args = ["kinit", principal]
- if options:
- args.extend(options)
- return self._run_in_env(args, password.encode('utf-8'), env)
-
- def kvno(self, principal, env=None):
- args = ["kvno", principal]
- return self._run_in_env(args, env)
-
- def kdestroy(self, all_ccaches=False, env=None):
- args = ["kdestroy"]
- if all_ccaches is True:
- args += ["-A"]
- retval, _, _ = self._run_in_env(args, env)
- return retval
-
- def kswitch(self, principal, env=None):
- args = ["kswitch", '-p', principal]
- retval, _, _ = self._run_in_env(args, env)
- return retval
-
- def _check_klist_l(self, line, exp_principal, exp_cache):
- try:
- princ, cache = line.split()
- except ValueError:
- return False
-
- if exp_cache is not None and cache != exp_cache:
- return False
-
- if exp_principal != princ:
- return False
-
- return True
-
- def num_princs(self, env=None):
- args = ["klist", "-l"]
- retval, out, err = self._run_in_env(args, extra_env=env)
- if retval != 0:
- return 0
-
- outlines = [ln for ln in out.split('\n') if len(ln) > 1]
- return len(outlines) - 2
-
- def list_princs(self, env=None):
- args = ["klist", "-l"]
- retval, out, err = self._run_in_env(args, extra_env=env)
- if retval == 1:
- raise NoPrincipals
- elif retval != 0:
- raise Exception("klist failed: %d: %s\n", retval, err)
-
- outlines = out.split('\n')
- if len(outlines) < 2:
- raise Exception("Not enough output from klist -l")
-
- return [ln for ln in outlines[2:] if len(ln) > 0]
-
- def list_times(self, env=None):
- p = self.spawn_in_env(['klist', '-A'])
- output = p.stdout.read().splitlines()
- for line in output:
- if not line:
- continue
-
- line_str = line.decode("utf-8")
- if line_str[0].isdigit():
- return line_str
-
- def has_principal(self, exp_principal, exp_cache=None, env=None):
- try:
- princlist = self.list_princs(env)
- except NoPrincipals:
- return False
-
- for line in princlist:
- matches = self._check_klist_l(line, exp_principal, exp_cache)
- if matches is True:
- return True
-
- return False
-
- def default_principal(self, env=None):
- principals = self.list_princs(env)
- return principals[0].split()[0]
-
- def _parse_klist_a(self, out):
- dflprinc = None
- thisrealm = None
- ccache_dict = dict()
-
- for line in [ln for ln in out.split('\n') if len(ln) > 0]:
- if line.startswith("Default principal"):
- dflprinc = line.split()[2]
- thisrealm = '@' + dflprinc.split('@')[1]
- elif thisrealm is not None and line.endswith(thisrealm):
- svc = line.split()[-1]
- if dflprinc in ccache_dict:
- ccache_dict[dflprinc].append(svc)
- else:
- ccache_dict[dflprinc] = [svc]
-
- return ccache_dict
-
- def list_all_princs(self, env=None):
- args = ["klist", "-A"]
- retval, out, err = self._run_in_env(args, extra_env=env)
- if retval == 1:
- raise NoPrincipals
- elif retval != 0:
- raise Exception("klist -A failed: %d: %s\n", retval, err)
-
- return self._parse_klist_a(out)
diff --git a/src/tests/intg/ldap_ent.py b/src/tests/intg/ldap_ent.py
deleted file mode 100644
index e5d1af43ac8..00000000000
--- a/src/tests/intg/ldap_ent.py
+++ /dev/null
@@ -1,258 +0,0 @@
-#
-# LDAP modlist generation
-#
-# Copyright (c) 2015 Red Hat, Inc.
-# Author: Nikolai Kondrashov
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-
-def user(base_dn, uid, uidNumber, gidNumber,
- userPassword=None,
- gecos=None,
- homeDirectory=None,
- loginShell=None,
- cn=None,
- sn=None,
- sshPubKey=(),
- mail=None):
- """
- Generate an RFC2307(bis) user add-modlist for passing to ldap.add*
- """
- uidNumber = str(uidNumber).encode('utf-8')
- gidNumber = str(gidNumber).encode('utf-8')
- user = (
- "uid=" + uid + ",ou=Users," + base_dn,
- [
- ('objectClass', [b'top', b'inetOrgPerson', b'mailRecipient',
- b'posixAccount', b'ldapPublicKey']),
- ('cn', [uidNumber if cn is None else cn.encode('utf-8')]),
- ('sn', [b'User' if sn is None else sn.encode('utf-8')]),
- ('uidNumber', [uidNumber]),
- ('gidNumber', [gidNumber]),
- ('userPassword', [b'Password' + uidNumber
- if userPassword is None
- else userPassword.encode('utf-8')]),
- ('homeDirectory', [b'/home/' + uid.encode('utf-8')
- if homeDirectory is None
- else homeDirectory.encode('utf-8')]),
- ('loginShell', [b'/bin/bash'
- if loginShell is None
- else loginShell.encode('utf-8')]),
- ]
- )
- if gecos is not None:
- user[1].append(('gecos', [gecos.encode('utf-8')]))
- if len(sshPubKey) > 0:
- pubkeys = [key.encode('utf-8') for key in sshPubKey]
- user[1].append(('sshPublicKey', pubkeys))
- if mail is not None:
- user[1].append(('mail', [mail.encode('utf-8')]))
- return user
-
-
-def group(base_dn, cn, gidNumber, member_uids=()):
- """
- Generate an RFC2307 group add-modlist for passing to ldap.add*.
- """
- gidNumber = str(gidNumber).encode('utf-8')
- attr_list = [
- ('objectClass', [b'top', b'posixGroup']),
- ('gidNumber', [gidNumber])
- ]
- if len(member_uids) > 0:
- mem_uids = [member.encode('utf-8') for member in member_uids]
- attr_list.append(('memberUid', mem_uids))
- return ("cn=" + cn + ",ou=Groups," + base_dn, attr_list)
-
-
-def group_bis(base_dn, cn, gidNumber, member_uids=(), member_gids=()):
- """
- Generate an RFC2307bis group add-modlist for passing to ldap.add*.
- """
- gidNumber = str(gidNumber).encode('utf-8')
- attr_list = [
- ('objectClass', [b'top', b'extensibleObject', b'groupOfNames']),
- ('gidNumber', [gidNumber])
- ]
- member_list = []
- for uid in member_uids:
- member_list.append("uid=" + uid + ",ou=Users," + base_dn)
- for gid in member_gids:
- member_list.append("cn=" + gid + ",ou=Groups," + base_dn)
- if len(member_list) > 0:
- mem_list = [member.encode('utf-8') for member in member_list]
- attr_list.append(('member', mem_list))
- return ("cn=" + cn + ",ou=Groups," + base_dn, attr_list)
-
-
-def netgroup(base_dn, cn, triples=(), members=()):
- """
- Generate an RFC2307bis netgroup add-modlist for passing to ldap.add*.
- """
- attr_list = [
- ('objectClass', [b'top', b'nisNetgroup'])
- ]
- if triples:
- triples = [triple.encode('utf-8') for triple in triples]
- attr_list.append(('nisNetgroupTriple', triples))
- if members:
- members = [member.encode('utf-8') for member in members]
- attr_list.append(('memberNisNetgroup', members))
- return ("cn=" + cn + ",ou=Netgroups," + base_dn, attr_list)
-
-
-def sudo_rule(base_dn, name, users=(), hosts=(), commands=()):
- """
- Generate a sudo rule for passing to ldap.add*
- """
- attr_list = [
- ('objectClass', [b'top', b'sudoRole']),
- ('cn', [name.encode('utf-8')])
- ]
-
- if len(users) > 0:
- sudo_user_list = [u.encode('utf-8') for u in users]
- attr_list.append(('sudoUser', sudo_user_list))
- if len(hosts) > 0:
- sudo_host_list = [h.encode('utf-8') for h in hosts]
- attr_list.append(('sudoHost', sudo_host_list))
- if len(commands) > 0:
- sudo_command_list = [cmd.encode('utf-8') for cmd in commands]
- attr_list.append(('sudoCommand', sudo_command_list))
- return ("cn=" + name + ",ou=sudoers," + base_dn, attr_list)
-
-
-def ip_host(base_dn, name, aliases=(), addresses=()):
- """
- Generate an RFC2307 ipHost add-modlist for passing to ldap.add*.
- """
- attr_list = [
- ('objectClass', [b'top', b'device', b'ipHost']),
- ]
- if (len(aliases)) > 0:
- alias_list = [alias.encode('utf-8') for alias in aliases]
- alias_list.insert(0, name.encode('utf-8'))
- attr_list.append(('cn', alias_list))
- else:
- attr_list.append(('cn', [name.encode('utf-8')]))
- if len(addresses) > 0:
- addr_list = [addr.encode('utf-8') for addr in addresses]
- attr_list.append(('ipHostNumber', addr_list))
- return ("cn=" + name + ",ou=Hosts," + base_dn, attr_list)
-
-
-def ip_net(base_dn, name, address, aliases=()):
- """
- Generate an RFC2307 ipNetwork add-modlist for passing to ldap.add*.
- """
- attr_list = [
- ('objectClass', [b'top', b'ipNetwork']),
- ('ipNetworkNumber', [address.encode('utf-8')]),
- ]
- if (len(aliases)) > 0:
- alias_list = [alias.encode('utf-8') for alias in aliases]
- alias_list.insert(0, name.encode('utf-8'))
- attr_list.append(('cn', alias_list))
- else:
- attr_list.append(('cn', [name.encode('utf-8')]))
- return ("cn=" + name + ",ou=Networks," + base_dn, attr_list)
-
-
-def ip_service(base_dn, name, proto, port, aliases=()):
- """
- Generate an RFC2307 ipService add-modlist for passing to ldap.add*.
- """
- attr_list = [
- ('objectClass', [b'top', b'ipService']),
- ('ipServicePort', [str(port).encode('utf-8')]),
- ('ipServiceProtocol', [proto.encode('utf-8')]),
- ]
- if (len(aliases)) > 0:
- alias_list = [alias.encode('utf-8') for alias in aliases]
- alias_list.insert(0, name.encode('utf-8'))
- attr_list.append(('cn', alias_list))
- else:
- attr_list.append(('cn', [name.encode('utf-8')]))
- return ("cn=" + name + ",ou=Services," + base_dn, attr_list)
-
-
-class List(list):
- """LDAP add-modlist list"""
-
- def __init__(self, base_dn):
- self.base_dn = base_dn
-
- def add_user(self, uid, uidNumber, gidNumber,
- base_dn=None,
- userPassword=None,
- gecos=None,
- homeDirectory=None,
- loginShell=None,
- cn=None,
- sn=None,
- sshPubKey=(),
- mail=None):
- """Add an RFC2307(bis) user add-modlist."""
- self.append(user(base_dn or self.base_dn,
- uid, uidNumber, gidNumber,
- userPassword=userPassword,
- gecos=gecos,
- homeDirectory=homeDirectory,
- loginShell=loginShell,
- cn=cn,
- sn=sn,
- sshPubKey=sshPubKey,
- mail=mail))
-
- def add_group(self, cn, gidNumber, member_uids=[],
- base_dn=None):
- """Add an RFC2307 group add-modlist."""
- self.append(group(base_dn or self.base_dn,
- cn, gidNumber, member_uids))
-
- def add_group_bis(self, cn, gidNumber,
- member_uids=[], member_gids=[],
- base_dn=None):
- """Add an RFC2307bis group add-modlist."""
- self.append(group_bis(base_dn or self.base_dn,
- cn, gidNumber,
- member_uids, member_gids))
-
- def add_netgroup(self, cn, triples=(), members=(), base_dn=None):
- """Add an RFC2307bis netgroup add-modlist."""
- self.append(netgroup(base_dn or self.base_dn,
- cn, triples, members))
-
- def add_sudo_rule(self, name,
- users=(), hosts=(), commands=(),
- base_dn=None):
- self.append(sudo_rule(base_dn or self.base_dn,
- name, users, hosts, commands))
-
- def add_host(self, name, aliases=[], addresses=[], base_dn=None):
- """Add an RFC2307 ipHost add-modlist."""
- self.append(ip_host(base_dn or self.base_dn,
- name, aliases, addresses))
-
- def add_ipnet(self, name, address, aliases=[], base_dn=None):
- """Add an RFC2307 ipNetwork add-modlist."""
- self.append(ip_net(base_dn or self.base_dn,
- name, address, aliases))
-
- def add_service(self, name, proto, port, aliases=[], base_dn=None):
- """Add an RFC2307 ipService add-modlist."""
- self.append(ip_service(base_dn or self.base_dn,
- name, proto, port, aliases))
diff --git a/src/tests/intg/nss_call.c b/src/tests/intg/nss_call.c
deleted file mode 100644
index a8c7d30f5c7..00000000000
--- a/src/tests/intg/nss_call.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- NSS module which calls glibc's user and group lookup functions again
-
- DO NOT USE THIS IN /etc/nsswitch.conf, it will cause an infinite loop.
-
- The main use case is to run proxy provider tests with cwrap's nss-wrapper.
- The proxy provider loads the NSS modules directly with dlopen() and is not
- using glibc's NSS mechanism. Since nss-wrapper just wraps the standard
- glibc calls and does not provide an NSS module on its own we have to use
- this workaround to make proxy provider work with nss-wrapper.
-
- Authors:
- Sumit Bose
-
- Copyright (c) 2023 Red Hat, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#define _DEFAULT_SOURCE
-#define _GNU_SOURCE
-
-#include
-#include
-#include
-#include
-#include
-
-
-
-#define NSSRET(r) return (((r) == 0) ? NSS_STATUS_SUCCESS : NSS_STATUS_NOTFOUND )
-
-enum nss_status _nss_call_getpwnam_r(const char *name, struct passwd *result,
- char *buffer, size_t buflen, int *errnop)
-{
- struct passwd *res;
- int ret = getpwnam_r(name, result, buffer, buflen, &res);
- NSSRET(ret);
-}
-
-enum nss_status _nss_call_getpwuid_r(uid_t uid, struct passwd *result,
- char *buffer, size_t buflen, int *errnop)
-{
- struct passwd *res;
- int ret = getpwuid_r(uid, result, buffer, buflen, &res);
- NSSRET(ret);
-}
-
-enum nss_status _nss_call_setpwent(void)
-{
- setpwent();
- return NSS_STATUS_SUCCESS;
-}
-
-enum nss_status _nss_call_getpwent_r(struct passwd *result,
- char *buffer, size_t buflen,
- int *errnop)
-{
- struct passwd *res;
- int ret = getpwent_r(result, buffer, buflen, &res);
- NSSRET(ret);
-}
-
-enum nss_status _nss_call_endpwent(void)
-{
- endpwent();
- return NSS_STATUS_SUCCESS;
-}
-
-enum nss_status _nss_call_getgrnam_r(const char *name, struct group *result,
- char *buffer, size_t buflen, int *errnop)
-{
- struct group *res;
- int ret = getgrnam_r(name, result, buffer, buflen, &res);
- NSSRET(ret);
-}
-
-enum nss_status _nss_call_getgrgid_r(gid_t gid, struct group *result,
- char *buffer, size_t buflen, int *errnop)
-{
- struct group *res;
- int ret = getgrgid_r(gid, result, buffer, buflen, &res);
- NSSRET(ret);
-}
-
-enum nss_status _nss_call_setgrent(void)
-{
- setgrent();
- return NSS_STATUS_SUCCESS;
-}
-
-enum nss_status _nss_call_getgrent_r(struct group *result,
- char *buffer, size_t buflen, int *errnop)
-{
- struct group *res;
- int ret = getgrent_r(result, buffer, buflen, &res);
- NSSRET(ret);
-}
-
-enum nss_status _nss_call_endgrent(void)
-{
- endgrent();
- return NSS_STATUS_SUCCESS;
-}
-
-enum nss_status _nss_call_initgroups_dyn(const char *user, gid_t group,
- long int *start, long int *size,
- gid_t **groups, long int limit,
- int *errnop)
-{
- int ngroups = 0;
- gid_t *grps = NULL;
- long int max_ret;
- long int i;
- int ret;
-
- ret = getgrouplist(user, group, grps, &ngroups);
- if (ret != -1) {
- return NSS_STATUS_UNAVAIL;
- }
-
- grps = malloc(ngroups * sizeof(gid_t));
- if (grps == NULL) {
- return NSS_STATUS_UNAVAIL;
- }
-
- max_ret = ngroups;
- /* check we have enough space in the buffer */
- if ((*size - *start) < ngroups) {
- long int newsize;
- gid_t *newgroups;
-
- newsize = *size + ngroups;
- if ((limit > 0) && (newsize > limit)) {
- newsize = limit;
- max_ret = newsize - *start;
- }
-
- newgroups = (gid_t *)realloc((*groups), newsize * sizeof(**groups));
- if (!newgroups) {
- free(grps);
- return NSS_STATUS_UNAVAIL;
- }
- *groups = newgroups;
- *size = newsize;
- }
-
- for (i = 0; i < max_ret; i++) {
- (*groups)[*start] = grps[i];
- *start += 1;
- }
- free(grps);
-
- return NSS_STATUS_SUCCESS;
-}
diff --git a/src/tests/intg/sss_netgroup_thread_test.c b/src/tests/intg/sss_netgroup_thread_test.c
deleted file mode 100644
index d3bee9b3e63..00000000000
--- a/src/tests/intg/sss_netgroup_thread_test.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- Helper program to test if innetgr() is thread-safe
-
- Authors:
- Sumit Bose
-
- Copyright (c) 2021 Red Hat, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-
-struct data {
- const char *group;
- const char *host;
- const char *user;
- const char *domain;
- bool *failed;
-};
-
-static void *full_netgroup(void *arg)
-{
- int ret;
- size_t c = 0;
- struct data *data = arg;
-
- do {
- ret = innetgr(data->group, data->host, data->user, data->domain);
- if (ret != 1) {
- *(data->failed) = true;
- }
- c++;
- } while (!*(data->failed) && c<100000);
-
- pthread_exit(NULL);
-}
-
-int main()
-{
- pthread_t thread[2];
- bool failed[2] = {false, false};
-
- struct data data[3] = {{"ng1", "host1", "user924", "domain1", &failed[0]},
- {"ng2", "host2", "user925", "domain2", &failed[1]},
- {NULL, NULL, NULL, NULL, NULL}};
-
-
- pthread_create(&thread[0], NULL, full_netgroup, &data[0]);
- pthread_create(&thread[1], NULL, full_netgroup, &data[1]);
-
- pthread_join(thread[1], NULL);
- pthread_join(thread[0], NULL);
-
- if (failed[0] || failed[1]) {
- printf ("Test failed.\n");
- return 1;
- }
-
- return 0;
-}
diff --git a/src/tests/intg/sssd_group.py b/src/tests/intg/sssd_group.py
deleted file mode 100644
index b6a37c5014c..00000000000
--- a/src/tests/intg/sssd_group.py
+++ /dev/null
@@ -1,132 +0,0 @@
-#
-# Module for simulation of utility "getent group -s sss" from coreutils
-#
-# Copyright (c) 2016 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-from ctypes import (c_int, c_char_p, c_ulong, POINTER, Structure,
- create_string_buffer)
-from sssd_nss import NssReturnCode, SssdNssError, nss_sss_ctypes_loader
-
-GROUP_BUFLEN = 1024
-
-
-class Group(Structure):
- _fields_ = [("gr_name", c_char_p),
- ("gr_passwd", c_char_p),
- ("gr_gid", c_int),
- ("gr_mem", POINTER(c_char_p))]
-
-
-def getgrnam_r(name, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getgrnam_r(const char *name,
- struct group *result,
- char *buffer,
- size_t buflen,
- int *errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getgrnam_r")
- func.restype = c_int
- func.argtypes = [c_char_p, POINTER(Group),
- c_char_p, c_ulong, POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
-
- name = name.encode('utf-8')
- res = func(c_char_p(name), result_p, buffer_p, buflen, errno)
-
- return (int(res), int(errno[0]), result_p)
-
-
-def getgrgid_r(gid, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getgrgid_r(gid_t gid,
- struct passwd *result,
- char *buffer,
- size_t buflen,
- int *errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getgrgid_r")
- func.restype = c_int
- func.argtypes = [c_ulong, POINTER(Group),
- c_char_p, c_ulong, POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
-
- res = func(gid, result_p, buffer_p, buflen, errno)
-
- return (int(res), int(errno[0]), result_p)
-
-
-def set_group_dict(res, result_p):
- if res != NssReturnCode.SUCCESS:
- return dict()
-
- group_dict = dict()
- group_dict['name'] = result_p[0].gr_name.decode('utf-8')
- group_dict['gid'] = result_p[0].gr_gid
- group_dict['mem'] = list()
-
- i = 0
- while result_p[0].gr_mem[i] is not None:
- grp_name = result_p[0].gr_mem[i].decode('utf-8')
- group_dict['mem'].append(grp_name)
- i = i + 1
-
- return group_dict
-
-
-def call_sssd_getgrnam(name):
- """
- A Python wrapper to retrieve a group by name. Returns:
- (res, group_dict)
- if res is NssReturnCode.SUCCESS, then group_dict contains the keys
- corresponding to the C passwd structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Group()
- result_p = POINTER(Group)(result)
- buff = create_string_buffer(GROUP_BUFLEN)
-
- res, errno, result_p = getgrnam_r(name, result_p, buff, GROUP_BUFLEN)
- if errno != 0:
- raise SssdNssError(errno, "getgrnam_r")
-
- group_dict = set_group_dict(res, result_p)
- return res, group_dict
-
-
-def call_sssd_getgrgid(gid):
- """
- A Python wrapper to retrieve a group by GID. Returns:
- (res, group_dict)
- if res is NssReturnCode.SUCCESS, then group_dict contains the keys
- corresponding to the C passwd structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Group()
- result_p = POINTER(Group)(result)
- buff = create_string_buffer(GROUP_BUFLEN)
-
- res, errno, result_p = getgrgid_r(gid, result_p, buff, GROUP_BUFLEN)
- if errno != 0:
- raise SssdNssError(errno, "getgrgid_r")
-
- group_dict = set_group_dict(res, result_p)
- return res, group_dict
diff --git a/src/tests/intg/sssd_hosts.py b/src/tests/intg/sssd_hosts.py
deleted file mode 100644
index 14732777dbb..00000000000
--- a/src/tests/intg/sssd_hosts.py
+++ /dev/null
@@ -1,142 +0,0 @@
-#
-# Module for simulation of utility "getent hosts -s sss" from coreutils
-#
-# Authors:
-# Samuel Cabrero
-#
-# Copyright (C) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-from ctypes import (c_int, c_char_p, c_ulong, POINTER,
- Structure, create_string_buffer)
-from sssd_nss import NssReturnCode, SssdNssError, nss_sss_ctypes_loader
-import socket
-from ipaddress import IPv4Address, IPv6Address
-
-HOST_BUFLEN = 1024
-
-
-class Hostent(Structure):
- _fields_ = [("h_name", c_char_p),
- ("h_aliases", POINTER(c_char_p)),
- ("h_addrtype", c_int),
- ("h_length", c_int),
- ("h_addr_list", POINTER(c_char_p))]
-
-
-def gethostbyname_r(name, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_gethostbyname_r(const char *name,
- struct hostent *result,
- char *buffer,
- size_t buflen,
- int *errnop,
- int *h_errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_gethostbyname_r")
- func.restype = c_int
- func.argtypes = [c_char_p, POINTER(Hostent),
- c_char_p, c_ulong, POINTER(c_int), POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
- h_errno = POINTER(c_int)(c_int(0))
-
- name = name.encode('utf-8')
- res = func(c_char_p(name), result_p, buffer_p, buflen, errno, h_errno)
-
- return (int(res), int(errno[0]), int(h_errno[0]), result_p)
-
-
-def gethostbyname2_r(name, af, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_gethostbyname2_r(const char *name,
- int af,
- struct hostent *result,
- char *buffer,
- size_t buflen,
- int *errnop,
- int *h_errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_gethostbyname2_r")
- func.restype = c_int
- func.argtypes = [c_char_p, c_int, POINTER(Hostent),
- c_char_p, c_ulong, POINTER(c_int), POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
- h_errno = POINTER(c_int)(c_int(0))
-
- name = name.encode('utf-8')
- res = func(c_char_p(name), af, result_p, buffer_p, buflen, errno, h_errno)
-
- return (int(res), int(errno[0]), int(h_errno[0]), result_p)
-
-
-def set_hostent_dict(res, result_p):
- if res != NssReturnCode.SUCCESS:
- return dict()
-
- hostent_dict = dict()
- hostent_dict['name'] = result_p[0].h_name.decode('utf-8')
- hostent_dict['aliases'] = list()
- hostent_dict['addrtype'] = result_p[0].h_addrtype
- hostent_dict['length'] = result_p[0].h_length
- hostent_dict['addresses'] = list()
-
- i = 0
- while result_p[0].h_aliases[i] is not None:
- alias = result_p[0].h_aliases[i].decode('utf-8')
- hostent_dict['aliases'].append(alias)
- i = i + 1
-
- i = 0
- while result_p[0].h_addr_list[i] is not None:
- length = result_p[0].h_length
- binaddr = result_p[0].h_addr_list[i][:length]
- if result_p[0].h_addrtype == socket.AF_INET:
- addr = IPv4Address(binaddr)
- addr = socket.inet_ntop(socket.AF_INET, addr.packed)
- elif result_p[0].h_addrtype == socket.AF_INET6:
- addr = IPv6Address(binaddr)
- addr = socket.inet_ntop(socket.AF_INET, addr.packed)
- else:
- raise Exception("Failed to parse IP address")
-
- hostent_dict['addresses'].append(addr)
- i = i + 1
-
- return hostent_dict
-
-
-def call_sssd_gethostbyname(name):
- """
- A Python wrapper to retrieve a host by name. Returns:
- (res, hostent_dict)
- if res is NssReturnCode.SUCCESS, then hostent_dict contains the keys
- corresponding to the C hostent structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Hostent()
- result_p = POINTER(Hostent)(result)
- buff = create_string_buffer(HOST_BUFLEN)
-
- (res, errno, h_errno, result_p) = gethostbyname_r(name, result_p,
- buff, HOST_BUFLEN)
- if errno != 0:
- raise SssdNssError(errno, "gethostbyname_r")
-
- hostent_dict = set_hostent_dict(res, result_p)
- return (res, h_errno, hostent_dict)
diff --git a/src/tests/intg/sssd_id.py b/src/tests/intg/sssd_id.py
deleted file mode 100644
index 3a45e3b6283..00000000000
--- a/src/tests/intg/sssd_id.py
+++ /dev/null
@@ -1,129 +0,0 @@
-#
-# Module for simulation of utility "id" from coreutils
-#
-# Copyright (c) 2015 Red Hat, Inc.
-# Author: Lukas Slebodnik
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-import pwd
-import grp
-from ctypes import (c_int, c_char, c_uint32, c_long, c_char_p,
- POINTER, pointer)
-from sssd_nss import NssReturnCode, nss_sss_ctypes_loader
-
-
-def call_sssd_initgroups(user, gid):
- """
- Function will initialize the supplementary group access list
- for given user. It will gather groups only provided by sssd.
-
- Arguments are the same as for C function initgroups
- @param string user name of user
- @param int gid the additional gid will be also added to the list.
-
- @return (int, int, List[int]) (err, errno, gids)
- gids should contain user group IDs if err is NssReturnCode.SUCCESS
- otherwise errno will contain non-zero value.
- """
- func = nss_sss_ctypes_loader('_nss_sss_initgroups_dyn')
-
- func.restype = c_int
- func.argtypes = [POINTER(c_char), c_uint32, POINTER(c_long),
- POINTER(c_long), POINTER(POINTER(c_uint32)), c_long,
- POINTER(c_int)]
-
- start = POINTER(c_long)(c_long(0))
- size = POINTER(c_long)(c_long(0))
- groups = POINTER(c_uint32)()
- p_groups = pointer(groups)
- limit = c_long(-1)
- errno = POINTER(c_int)(c_int(0))
-
- res = func(c_char_p(user.encode('utf-8)')), c_uint32(gid), start, size,
- p_groups, limit, errno)
-
- gids = []
- if res == NssReturnCode.SUCCESS:
- gids_count = size[0]
- assert gids_count > 0, "_nss_sss_initgroups_dyn should return " \
- "one gid"
-
- for i in range(0, gids_count):
- gids.append(int(p_groups.contents[i]))
-
- # add primary group if missing
- if gid not in gids:
- gids.append(gid)
-
- return (int(res), errno[0], gids)
-
-
-def get_user_gids(user):
- """
- Function will initialize the supplementary group access list
- for given user. It will gather groups only provided by sssd.
-
- Arguments are the same as for C function initgroups
- @param string user name of user
-
- @return (int, int, List[int]) (err, errno, gids)
- gids should contain user group IDs if err is NssReturnCode.SUCCESS
- otherwise errno will contain non-zero value.
- """
- pwd_user = pwd.getpwnam(user)
- uid = pwd_user.pw_uid
- gid = pwd_user.pw_gid
-
- user = pwd.getpwuid(uid).pw_name
-
- return call_sssd_initgroups(user, gid)
-
-
-def gid_to_str(gid):
- """
- Function will map numeric GID into names.
- If there isn't a group for GID (getgrgid failed)
- then the function will return decimal representation of ID.
-
- @param int gid ID of groups which should be converted to string.
- @return string name of group with requested ID or decimal
- representation of ID
- """
- try:
- return grp.getgrgid(gid).gr_name
- except KeyError:
- return str(gid)
-
-
-def get_user_groups(user):
- """
- Function will initialize the supplementary group access list
- for given user. It will gather groups only provided by sssd.
-
- Arguments are the same as for C function initgroups
- @param string user name of user
-
- @return (int, int, List[string]) (err, errno, groups)
- groups should contain names of user groups
- if err is NssReturnCode.SUCCESS
- otherwise errno will contain non-zero value.
- """
- (res, errno, gids) = get_user_gids(user)
- groups = []
-
- if res == NssReturnCode.SUCCESS:
- groups = [gid_to_str(gid) for gid in gids]
-
- return (res, errno, groups)
diff --git a/src/tests/intg/sssd_ldb.py b/src/tests/intg/sssd_ldb.py
deleted file mode 100644
index 746dbfa19df..00000000000
--- a/src/tests/intg/sssd_ldb.py
+++ /dev/null
@@ -1,96 +0,0 @@
-#
-# SSSD integration test - access the ldb cache
-#
-# Copyright (c) 2016 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import os
-import ldb
-import config
-
-
-class CacheType(object):
- sysdb = 1
- timestamps = 2
-
-
-class TsCacheEntry(object):
- user = 1
- group = 2
-
-
-class SssdLdb(object):
- def __init__(self, domain_name):
- self._domain_name = domain_name
- self._sysdb = self._create_dbconn(CacheType.sysdb,
- domain_name)
- self._timestamps = self._create_dbconn(CacheType.timestamps,
- domain_name)
-
- def _create_dbconn(self, cache_type, domain_name):
- if cache_type == CacheType.sysdb:
- db_path = os.path.join(config.DB_PATH,
- "cache_%s.ldb" % domain_name)
- elif cache_type == CacheType.timestamps:
- db_path = os.path.join(config.DB_PATH,
- "timestamps_%s.ldb" % domain_name)
- else:
- raise ValueError("Unknown cache type\n")
-
- pyldb = ldb.Ldb()
- pyldb.connect(db_path)
- return pyldb
-
- def _get_dbconn(self, cache_type):
- dbconn = None
- if cache_type == CacheType.sysdb:
- dbconn = self._sysdb
- elif cache_type == CacheType.timestamps:
- dbconn = self._timestamps
- return dbconn
-
- def _entry_basedn(self, entry_type):
- if entry_type == TsCacheEntry.user:
- rdn = "users"
- elif entry_type == TsCacheEntry.group:
- rdn = "groups"
- else:
- raise ValueError("Unknown entry type\n")
- return "cn=%s,cn=%s,cn=sysdb" % (rdn, self._domain_name)
-
- def _basedn(self, name, domain, entry_type):
- return "name=%s@%s,%s" % (name, domain.lower(),
- self._entry_basedn(entry_type))
-
- def get_entry_attr(self, cache_type, entry_type, name, domain, attr):
- dbconn = self._get_dbconn(cache_type)
- basedn = self._basedn(name, domain, entry_type)
-
- res = dbconn.search(base=basedn, scope=ldb.SCOPE_BASE, attrs=[attr])
- if res.count != 1:
- return None
-
- return res.msgs[0].get(attr).get(0)
-
- def invalidate_entry(self, name, entry_type, domain):
- dbconn = self._get_dbconn(CacheType.timestamps)
-
- m = ldb.Message()
- m.dn = ldb.Dn(dbconn, self._basedn(name, domain, entry_type))
- m["dataExpireTimestamp"] = ldb.MessageElement(str(1),
- ldb.FLAG_MOD_REPLACE,
- "dataExpireTimestamp")
- dbconn.modify(m)
diff --git a/src/tests/intg/sssd_netgroup.py b/src/tests/intg/sssd_netgroup.py
deleted file mode 100644
index 81d017fa3dc..00000000000
--- a/src/tests/intg/sssd_netgroup.py
+++ /dev/null
@@ -1,247 +0,0 @@
-#
-# Module for simulation of utility "getent netgroup -s sss" from coreutils
-#
-# Copyright (c) 2016 Red Hat, Inc.
-# Author: Lukas Slebodnik
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-from ctypes import (c_int, c_char, c_char_p, c_size_t, c_void_p, c_ulong,
- POINTER, Structure, Union, create_string_buffer, get_errno)
-from sssd_nss import NssReturnCode, nss_sss_ctypes_loader
-
-
-class NetgroupType(object):
- """ 'enum' class for type of netgroup """
- TRIPLE_VAL = 0
- GROUP_VAL = 1
-
-
-class Triple(Structure):
- _fields_ = [("host", c_char_p),
- ("user", c_char_p),
- ("domain", c_char_p)]
-
-
-class Val(Union):
- _fields_ = [("triple", Triple),
- ("group", c_char_p)]
-
-
-class Idx(Union):
- _fields_ = [("cursor", POINTER(c_char)),
- ("position", c_ulong)]
-
-
-class NameList(Structure):
- pass
-
-
-NameList._fields_ = [("next", POINTER(NameList)),
- ("name", POINTER(c_char))]
-
-
-class Netgrent(Structure):
- _fields_ = [("type", c_int),
- ("val", Val),
- ("data", POINTER(c_char)),
- ("data_size", c_size_t),
- ("idx", Idx),
- ("first", c_int),
- ("known_groups", POINTER(NameList)),
- ("needed_groups", POINTER(NameList)),
- ("nip", c_void_p)]
-
-
-class NetgroupRetriever(object):
- def __init__(self, name):
- self.name = name.encode('utf-8')
- self.needed_groups = []
- self.known_groups = []
- self.netgroups = []
-
- @staticmethod
- def _setnetgrent(netgroup):
- """
- This private method is ctypes wrapper for
- enum nss_status _nss_sss_setnetgrent(const char *netgroup,
- struct __netgrent *result)
-
- @param string name name of netgroup
-
- @return (int, POINTER(Netgrent)) (err, result_p)
- err is a constant from class NssReturnCode and in case of SUCCESS
- result_p will contain POINTER(Netgrent) which can be used in
- _getnetgrent_r or _getnetgrent_r.
- """
- func = nss_sss_ctypes_loader('_nss_sss_setnetgrent')
- func.restype = c_int
- func.argtypes = [c_char_p, POINTER(Netgrent)]
-
- result = Netgrent()
- result_p = POINTER(Netgrent)(result)
-
- res = func(c_char_p(netgroup), result_p)
-
- return (int(res), result_p)
-
- @staticmethod
- def _getnetgrent_r(result_p, buff, buff_len):
- """
- This private method is ctypes wrapper for
- enum nss_status _nss_sss_getnetgrent_r(struct __netgrent *result,
- char *buffer, size_t buflen,
- int *errnop)
- @param POINTER(Netgrent) result_p pointer to initialized C structure
- struct __netgrent
- @param ctypes.c_char_Array buff buffer used by C functions
- @param int buff_len size of c_char_Array passed as a parameter buff
-
- @return (int, int, List[(string, string, string])
- (err, errno, netgroups)
- if err is NssReturnCode.SUCCESS netgroups will contain list of
- touples. Each touple will consist of 3 elements either string or
- """
- func = nss_sss_ctypes_loader('_nss_sss_getnetgrent_r')
- func.restype = c_int
- func.argtypes = [POINTER(Netgrent), POINTER(c_char), c_size_t,
- POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
-
- res = func(result_p, buff, buff_len, errno)
-
- return (int(res), int(errno[0]), result_p)
-
- @staticmethod
- def _endnetgrent(result_p):
- """
- This private method is ctypes wrapper for
- enum nss_status _nss_sss_endnetgrent(struct __netgrent *result)
-
- @param POINTER(Netgrent) result_p pointer to initialized C structure
- struct __netgrent
-
- @return int a constant from class NssReturnCode
- """
- func = nss_sss_ctypes_loader('_nss_sss_endnetgrent')
- func.restype = c_int
- func.argtypes = [POINTER(Netgrent)]
-
- res = func(result_p)
-
- return int(res)
-
- def get_netgroups(self):
- """
- Function will return netgroup triplets for given user. All nested
- netgroups will be retrieved as part of executions and will content
- will be merged with direct triplets.
- Missing nested netgroups will not cause failure and are considered
- as an empty netgroup without triplets.
-
- @param string name name of netgroup
-
- @return (int, int, List[(string, string, string])
- (err, errno, netgroups)
- if err is NssReturnCode.SUCCESS netgroups will contain list of
- touples. Each touple will consist of 3 elements either string or
- None (host, user, domain).
- """
- res, errno, result = self._flat_fetch_netgroups(self.name)
- if res != NssReturnCode.SUCCESS:
- return (res, errno, self.netgroups)
-
- self.netgroups += result
-
- while self.needed_groups:
- name = self.needed_groups.pop(0)
-
- nest_res, nest_errno, result = self._flat_fetch_netgroups(name)
- # do not fail for missing nested netgroup
- if nest_res not in (NssReturnCode.SUCCESS, NssReturnCode.NOTFOUND):
- return (nest_res, nest_errno, self.netgroups)
-
- self.netgroups = result + self.netgroups
-
- return (res, errno, self.netgroups)
-
- def _flat_fetch_netgroups(self, name):
- """
- Function will return netgroup triplets for given user. The nested
- netgroups will not be returned. Missing nested netgroups will be
- appended to the array needed_groups
-
- @param string name name of netgroup
-
- @return (int, int, List[(string, string, string])
- (err, errno, netgroups)
- if err is NssReturnCode.SUCCESS netgroups will contain list of
- touples. Each touple will consist of 3 elements either string or
- None (host, user, domain).
- """
- buff_len = 1024 * 1024
- buff = create_string_buffer(buff_len)
-
- result = []
-
- res, result_p = self._setnetgrent(name)
- if res != NssReturnCode.SUCCESS:
- return (res, get_errno(), result)
-
- res, errno, result_p = self._getnetgrent_r(result_p, buff, buff_len)
- while res == NssReturnCode.SUCCESS:
- if result_p[0].type == NetgroupType.GROUP_VAL:
- nested_netgroup = result_p[0].val.group
- if nested_netgroup not in self.known_groups:
- self.needed_groups.append(nested_netgroup)
- self.known_groups.append(nested_netgroup)
-
- if result_p[0].type == NetgroupType.TRIPLE_VAL:
- triple = result_p[0].val.triple
- result.append((triple.host and triple.host.decode('utf-8')
- or "",
- triple.user and triple.user.decode('utf-8')
- or "",
- triple.domain and triple.domain.decode('utf-8')
- or ""))
-
- res, errno, result_p = self._getnetgrent_r(result_p, buff,
- buff_len)
-
- if res != NssReturnCode.RETURN:
- return (res, errno, result)
-
- res = self._endnetgrent(result_p)
-
- return (res, errno, result)
-
-
-def get_sssd_netgroups(name):
- """
- Function will return netgroup triplets for given user. It will gather
- netgroups only provided by sssd.
- The equivalent of "getent netgroup -s sss user"
-
- @param string name name of netgroup
-
- @return (int, int, List[(string, string, string]) (err, errno, netgroups)
- if err is NssReturnCode.SUCCESS netgroups will contain list of touples.
- Each touple will consist of 3 elements either string or None
- (host, user, domain).
- """
-
- retriever = NetgroupRetriever(name)
-
- return retriever.get_netgroups()
diff --git a/src/tests/intg/sssd_nets.py b/src/tests/intg/sssd_nets.py
deleted file mode 100644
index a64b5adc20e..00000000000
--- a/src/tests/intg/sssd_nets.py
+++ /dev/null
@@ -1,147 +0,0 @@
-#
-# Module for simulation of utility "getent networks -s sss" from coreutils
-#
-# Authors:
-# Samuel Cabrero
-#
-# Copyright (C) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-from ctypes import (c_int, c_char_p, c_ulong, c_uint32, POINTER,
- Structure, create_string_buffer)
-from sssd_nss import NssReturnCode, SssdNssError, nss_sss_ctypes_loader
-import socket
-from ipaddress import IPv4Address
-from struct import unpack
-
-IP_NETWORK_BUFLEN = 1024
-
-
-class Netent(Structure):
- _fields_ = [("n_name", c_char_p),
- ("n_aliases", POINTER(c_char_p)),
- ("n_addrtype", c_int),
- ("n_net", c_uint32)]
-
-
-def getnetbyname_r(name, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getnetbyname_r(const char *name,
- struct netent *result,
- char *buffer, size_t buflen,
- int *errnop, int *h_errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getnetbyname_r")
- func.restype = c_int
- func.argtypes = [c_char_p, POINTER(Netent),
- c_char_p, c_ulong, POINTER(c_int), POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
- h_errno = POINTER(c_int)(c_int(0))
-
- name = name.encode('utf-8')
- res = func(c_char_p(name), result_p, buffer_p, buflen, errno, h_errno)
-
- return (int(res), int(errno[0]), int(h_errno[0]), result_p)
-
-
-def getnetbyaddr_r(addr, af, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getnetbyaddr_r(uint32_t addr, int type,
- struct netent *result,
- char *buffer, size_t buflen,
- int *errnop, int *h_errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getnetbyaddr_r")
- func.restype = c_int
- func.argtypes = [c_uint32, c_int, POINTER(Netent),
- c_char_p, c_ulong, POINTER(c_int), POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
- h_errno = POINTER(c_int)(c_int(0))
-
- res = func(addr, af, result_p, buffer_p, buflen, errno, h_errno)
-
- return (int(res), int(errno[0]), int(h_errno[0]), result_p)
-
-
-def set_netent_dict(res, result_p):
- if res != NssReturnCode.SUCCESS:
- return dict()
-
- netent_dict = dict()
- netent_dict['name'] = result_p[0].n_name.decode('utf-8')
- netent_dict['aliases'] = list()
- netent_dict['addrtype'] = result_p[0].n_addrtype
- netent_dict['address'] = result_p[0].n_net
-
- i = 0
- while result_p[0].n_aliases[i] is not None:
- alias = result_p[0].n_aliases[i].decode('utf-8')
- netent_dict['aliases'].append(alias)
- i = i + 1
-
- return netent_dict
-
-
-def call_sssd_getnetbyname(name):
- """
- A Python wrapper to retrieve an IP network by name. Returns:
- (res, netent_dict)
- if res is NssReturnCode.SUCCESS, then netent_dict contains the keys
- corresponding to the C netent structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Netent()
- result_p = POINTER(Netent)(result)
- buff = create_string_buffer(IP_NETWORK_BUFLEN)
-
- (res, errno, h_errno, result_p) = getnetbyname_r(name, result_p,
- buff, IP_NETWORK_BUFLEN)
- if errno != 0:
- raise SssdNssError(errno, "getnetbyname_r")
-
- netent_dict = set_netent_dict(res, result_p)
- return (res, h_errno, netent_dict)
-
-
-def call_sssd_getnetbyaddr(addrstr, af):
- """
- A Python wrapper to retrieve an IP network by address. Returns:
- (res, netent_dict)
- if res is NssReturnCode.SUCCESS, then netent_dict contains the keys
- corresponding to the C netent structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Netent()
- result_p = POINTER(Netent)(result)
- buff = create_string_buffer(IP_NETWORK_BUFLEN)
-
- if isinstance(addrstr, bytes):
- addrstr = addrstr.decode('utf-8')
- addr = IPv4Address(addrstr)
- binaddr = unpack('.
-#
-import config
-import ctypes
-
-
-class NssReturnCode(object):
- """ 'enum' class for name service switch return code """
- TRYAGAIN = -2,
- UNAVAIL = -1
- NOTFOUND = 0
- SUCCESS = 1
- RETURN = 2
-
-
-class HostError(object):
- """ 'enum' class for h_errno (glibc >= 2.19) """
- HOST_NOT_FOUND = 1
- TRY_AGAIN = 2
- NO_RECOVERY = 3
- NO_DATA = 4
-
- @classmethod
- def tostring(cls, val):
- if (val == 1):
- return "HOST_NOT_FOUND"
- if (val == 2):
- return "TRY_AGAIN"
- if (val == 3):
- return "NO_RECOVERY"
- if (val == 4):
- return "NO_DATA"
- return "UNKNOWN"
-
-
-class SssdNssError(Exception):
- """ Raised when one of the NSS operations fail """
- def __init__(self, errno, nssop):
- self.errno = errno
- self.nssop = nssop
-
- def __str__(self):
- return "NSS operation %s failed %d" % (self.nssop, self.errno)
-
-
-class SssdNssHostError(Exception):
- """ Raised when one of the NSS hosts operations fail """
- def __init__(self, h_errno, nssop):
- self.h_errno = h_errno
- self.nssop = nssop
-
- def __str__(self):
- str_herr = HostError.tostring(self.h_errno)
- return "NSS host operation %s failed: %s" % (self.nssop, str_herr)
-
-
-def nss_sss_ctypes_loader(func_name):
- libnss_sss_path = config.NSS_MODULE_DIR + "/libnss_sss.so.2"
- libnss_sss = ctypes.cdll.LoadLibrary(libnss_sss_path)
- func = getattr(libnss_sss, func_name)
- return func
diff --git a/src/tests/intg/sssd_passwd.py b/src/tests/intg/sssd_passwd.py
deleted file mode 100644
index f8c91da7a0b..00000000000
--- a/src/tests/intg/sssd_passwd.py
+++ /dev/null
@@ -1,210 +0,0 @@
-#
-# Module for simulation of utility "getent passwd -s sss" from coreutils
-#
-# Copyright (c) 2016 Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-from ctypes import (c_int, c_char_p, c_ulong, POINTER,
- Structure, create_string_buffer, get_errno)
-from sssd_nss import NssReturnCode, SssdNssError, nss_sss_ctypes_loader
-
-PASSWD_BUFLEN = 1024
-
-
-class Passwd(Structure):
- _fields_ = [("pw_name", c_char_p),
- ("pw_passwd", c_char_p),
- ("pw_uid", c_int),
- ("pw_gid", c_int),
- ("pw_gecos", c_char_p),
- ("pw_dir", c_char_p),
- ("pw_shell", c_char_p)]
-
-
-def set_user_dict(res, result_p):
- if res != NssReturnCode.SUCCESS:
- return dict()
-
- user_dict = dict()
- user_dict['name'] = result_p[0].pw_name.decode('utf-8')
- user_dict['passwd'] = result_p[0].pw_passwd.decode('utf-8')
- user_dict['uid'] = result_p[0].pw_uid
- user_dict['gid'] = result_p[0].pw_gid
- user_dict['gecos'] = result_p[0].pw_gecos.decode('utf-8')
- user_dict['dir'] = result_p[0].pw_dir.decode('utf-8')
- user_dict['shell'] = result_p[0].pw_shell.decode('utf-8')
- return user_dict
-
-
-def getpwnam_r(name, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getpwnam_r(const char *name,
- struct passwd *result,
- char *buffer,
- size_t buflen,
- int *errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getpwnam_r")
- func.restype = c_int
- func.argtypes = [c_char_p, POINTER(Passwd),
- c_char_p, c_ulong, POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
-
- name = name.encode('utf-8')
- res = func(c_char_p(name), result_p, buffer_p, buflen, errno)
-
- return (int(res), int(errno[0]), result_p)
-
-
-def getpwuid_r(uid, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getpwuid_r(uid_t uid,
- struct passwd *result,
- char *buffer,
- size_t buflen,
- int *errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getpwuid_r")
- func.restype = c_int
- func.argtypes = [c_ulong, POINTER(Passwd),
- c_char_p, c_ulong, POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
-
- res = func(uid, result_p, buffer_p, buflen, errno)
-
- return (int(res), int(errno[0]), result_p)
-
-
-def setpwent():
- """
- ctypes wrapper for:
- void setpwent(void)
- """
- func = nss_sss_ctypes_loader("_nss_sss_setpwent")
- func.argtypes = []
-
- res = func()
- assert res == NssReturnCode.SUCCESS
-
- errno = get_errno()
- if errno != 0:
- raise SssdNssError(errno, "setpwent")
-
-
-def endpwent():
- """
- ctypes wrapper for:
- void endpwent(void)
- """
- func = nss_sss_ctypes_loader("_nss_sss_endpwent")
- func.argtypes = []
-
- res = func()
- assert res == NssReturnCode.SUCCESS
-
- errno = get_errno()
- if errno != 0:
- raise SssdNssError(errno, "endpwent")
-
-
-def getpwent_r(result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getpwent_r(struct passwd *result,
- char *buffer, size_t buflen,
- int *errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getpwent_r")
- func.restype = c_int
- func.argtypes = [POINTER(Passwd), c_char_p, c_ulong, POINTER(c_int)]
-
- errno = POINTER(c_int)(c_int(0))
-
- res = func(result_p, buffer_p, buflen, errno)
- return (int(res), int(errno[0]), result_p)
-
-
-def getpwent():
- result = Passwd()
- result_p = POINTER(Passwd)(result)
- buff = create_string_buffer(PASSWD_BUFLEN)
-
- res, errno, result_p = getpwent_r(result_p, buff, PASSWD_BUFLEN)
- if errno != 0:
- raise SssdNssError(errno, "getpwent_r")
-
- user_dict = set_user_dict(res, result_p)
- return res, user_dict
-
-
-def call_sssd_getpwnam(name):
- """
- A Python wrapper to retrieve a user by name. Returns:
- (res, user_dict)
- if res is NssReturnCode.SUCCESS, then user_dict contains the keys
- corresponding to the C passwd structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Passwd()
- result_p = POINTER(Passwd)(result)
- buff = create_string_buffer(PASSWD_BUFLEN)
-
- res, errno, result_p = getpwnam_r(name, result_p, buff, PASSWD_BUFLEN)
- if errno != 0:
- raise SssdNssError(errno, "getpwnam_r")
-
- user_dict = set_user_dict(res, result_p)
- return res, user_dict
-
-
-def call_sssd_getpwuid(uid):
- """
- A Python wrapper to retrieve a user by UID. Returns:
- (res, user_dict)
- if res is NssReturnCode.SUCCESS, then user_dict contains the keys
- corresponding to the C passwd structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Passwd()
- result_p = POINTER(Passwd)(result)
- buff = create_string_buffer(PASSWD_BUFLEN)
-
- res, errno, result_p = getpwuid_r(uid, result_p, buff, PASSWD_BUFLEN)
- if errno != 0:
- raise SssdNssError(errno, "getpwuid_r")
-
- user_dict = set_user_dict(res, result_p)
- return res, user_dict
-
-
-def call_sssd_enumeration():
- """
- enumerate users from sssd module only
- """
- setpwent()
- user_list = []
-
- res, user = getpwent()
- while res == NssReturnCode.SUCCESS:
- user_list.append(user)
- res, user = getpwent()
-
- endpwent()
- return user_list
diff --git a/src/tests/intg/sssd_services.py b/src/tests/intg/sssd_services.py
deleted file mode 100644
index e114cc3766e..00000000000
--- a/src/tests/intg/sssd_services.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#
-# Module for simulation of utility "getent services -s sss" from coreutils
-#
-# Authors:
-# Samuel Cabrero
-#
-# Copyright (C) 2025 SUSE LINUX GmbH, Nuernberg, Germany.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-from ctypes import (
- c_int,
- c_char_p,
- c_ulong,
- POINTER,
- Structure,
- create_string_buffer,
-)
-from sssd_nss import NssReturnCode, SssdNssError, nss_sss_ctypes_loader
-import socket
-
-SERVICE_BUFLEN = 1024
-
-
-# struct servent from netdb.h
-class Servent(Structure):
- _fields_ = [
- ("s_name", c_char_p),
- ("s_aliases", POINTER(c_char_p)),
- ("s_port", c_int),
- ("s_proto", c_char_p),
- ]
-
-
-def getservbyname_r(name, proto, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getservbyname_r(const char *name,
- const char *protocol,
- struct servent *result,
- char *buffer, size_t buflen,
- int *errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getservbyname_r")
- func.restype = c_int
- func.argtypes = [
- c_char_p,
- c_char_p,
- POINTER(Servent),
- c_char_p,
- c_ulong,
- POINTER(c_int),
- ]
-
- errno = POINTER(c_int)(c_int(0))
-
- name = name.encode("utf-8")
- proto = proto.encode("utf-8")
- res = func(c_char_p(name), c_char_p(proto), result_p, buffer_p, buflen, errno)
-
- return (int(res), int(errno[0]), result_p)
-
-
-def getservbyport_r(port, proto, result_p, buffer_p, buflen):
- """
- ctypes wrapper for:
- enum nss_status _nss_sss_getservbyport_r(int port, const char *protocol,
- struct servent *result,
- char *buffer, size_t buflen,
- int *errnop)
- """
- func = nss_sss_ctypes_loader("_nss_sss_getservbyport_r")
- func.restype = c_int
- func.argtypes = [
- c_int,
- c_char_p,
- POINTER(Servent),
- c_char_p,
- c_ulong,
- POINTER(c_int),
- ]
-
- errno = POINTER(c_int)(c_int(0))
-
- port = socket.htons(port)
- proto = proto.encode("utf-8")
- res = func(port, c_char_p(proto), result_p, buffer_p, buflen, errno)
-
- return (int(res), int(errno[0]), result_p)
-
-
-def set_servent_dict(res, result_p):
- if res != NssReturnCode.SUCCESS:
- return dict()
-
- servent_dict = dict()
- servent_dict["name"] = result_p[0].s_name.decode("utf-8")
- servent_dict["aliases"] = list()
- servent_dict["port"] = result_p[0].s_port
- servent_dict["proto"] = result_p[0].s_proto
-
- i = 0
- while result_p[0].s_aliases[i] is not None:
- alias = result_p[0].s_aliases[i].decode("utf-8")
- servent_dict["aliases"].append(alias)
- i = i + 1
-
- return servent_dict
-
-
-def call_sssd_getservbyname(name, proto):
- """
- A Python wrapper to retrieve a service by name and protocol. Returns:
- (res, servent_dict)
- if res is NssReturnCode.SUCCESS, then servent_dict contains the keys
- corresponding to the C servent structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Servent()
- result_p = POINTER(Servent)(result)
- buff = create_string_buffer(SERVICE_BUFLEN)
-
- (res, errno, result_p) = getservbyname_r(
- name, proto, result_p, buff, SERVICE_BUFLEN
- )
- if errno != 0:
- raise SssdNssError(errno, "getservbyname_r")
-
- servent_dict = set_servent_dict(res, result_p)
- return (res, servent_dict)
-
-
-def call_sssd_getservbyport(port, proto):
- """
- A Python wrapper to retrieve a service by port and protocol. Returns:
- (res, servent_dict)
- if res is NssReturnCode.SUCCESS, then servent_dict contains the keys
- corresponding to the C servent structure fields. Otherwise, the dictionary
- is empty and errno indicates the error code
- """
- result = Servent()
- result_p = POINTER(Servent)(result)
- buff = create_string_buffer(SERVICE_BUFLEN)
-
- (res, errno, result_p) = getservbyport_r(
- port, proto, result_p, buff, SERVICE_BUFLEN
- )
- if errno != 0:
- raise SssdNssError(errno, "getservbyport_r")
-
- servent_dict = set_servent_dict(res, result_p)
- return (res, servent_dict)
diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py
deleted file mode 100644
index cb864523958..00000000000
--- a/src/tests/intg/test_pam_responder.py
+++ /dev/null
@@ -1,993 +0,0 @@
-#
-# Test for the PAM responder
-#
-# Copyright (c) 2018 Red Hat, Inc.
-# Author: Sumit Bose
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-"""
-Tests for the PAM responder
-"""
-import os
-import stat
-import signal
-import errno
-import subprocess
-import time
-
-import config
-import intg.ds_openldap
-import kdc
-
-import pytest
-
-from intg.util import unindent
-
-LDAP_BASE_DN = "dc=example,dc=com"
-
-def provider_list():
- # The comma is required to indicate a list with the string 'proxy' as
- # only item, without it the string 'proxy' will be interpreted as list
- # with five letters.
- return ('proxy',)
-
-
-class provider_switch:
- def __init__(self, p):
- if p == 'proxy':
- self.p = "id_provider = proxy\nlocal_auth_policy = only\nproxy_lib_name = call\n"
- elif p == 'proxy_password':
- self.p = "id_provider = proxy\nproxy_lib_name = call\nproxy_pam_target = sssd-shadowutils\n"
- elif p == 'proxy_password_with_sc':
- self.p = "id_provider = proxy\nlocal_auth_policy = enable:smartcard\nproxy_lib_name = call\nproxy_pam_target = sssd-shadowutils\n"
- else:
- self.p = none
-
-
-@pytest.fixture(scope="module")
-def ad_inst(request):
- """Fake AD server instance fixture"""
- instance = intg.ds_openldap.FakeAD(
- config.PREFIX, 10389, LDAP_BASE_DN,
- "cn=admin", "Secret123"
- )
-
- try:
- instance.setup()
- except Exception:
- instance.teardown()
- raise
- request.addfinalizer(instance.teardown)
- return instance
-
-
-@pytest.fixture(scope="module")
-def ldap_conn(request, ad_inst):
- """LDAP server connection fixture"""
- ldap_conn = ad_inst.bind()
- ldap_conn.ad_inst = ad_inst
- request.addfinalizer(ldap_conn.unbind_s)
- return ldap_conn
-
-
-def format_basic_conf(ldap_conn):
- """Format a basic SSSD configuration"""
- return unindent("""\
- [sssd]
- domains = FakeAD
- services = pam, nss
-
- [nss]
-
- [pam]
- debug_level = 10
-
- [domain/FakeAD]
- debug_level = 10
- ldap_search_base = {ldap_conn.ad_inst.base_dn}
- ldap_referrals = false
-
- id_provider = ldap
- auth_provider = ldap
- chpass_provider = ldap
- access_provider = ldap
-
- ldap_uri = {ldap_conn.ad_inst.ldap_url}
- ldap_default_bind_dn = {ldap_conn.ad_inst.admin_dn}
- ldap_default_authtok_type = password
- ldap_default_authtok = {ldap_conn.ad_inst.admin_pw}
-
- ldap_schema = ad
- ldap_id_mapping = true
- ldap_idmap_default_domain_sid = S-1-5-21-1305200397-2901131868-73388776
- case_sensitive = False
-
- [prompting/password]
- password_prompt = My global prompt
-
- [prompting/password/pam_sss_alt_service]
- password_prompt = My alt service prompt
- """).format(**locals())
-
-USER1 = dict(name='user1', passwd='x', uid=10001, gid=20001,
- gecos='User for tests',
- dir='/home/user1',
- shell='/bin/bash')
-
-USER2 = dict(name='user2', passwd='x', uid=10002, gid=20002,
- gecos='User with no Smartcard mapping',
- dir='/home/user2',
- shell='/bin/bash')
-
-
-def format_pam_cert_auth_conf(config, provider):
- """Format a basic SSSD configuration"""
- return unindent("""\
- [sssd]
- debug_level = 10
- domains = auth_only
- services = pam, nss
-
- [nss]
- debug_level = 10
-
- [pam]
- pam_cert_auth = True
- pam_p11_allowed_services = +pam_sss_service, +pam_sss_sc_required, \
- +pam_sss_try_sc, +pam_sss_allow_missing_name
- pam_cert_db_path = {config.PAM_CERT_DB_PATH}
- p11_uri = pkcs11:manufacturer=SoftHSM%20project; \
- token=SSSD%20Test%20Token
- p11_child_timeout = 5
- p11_wait_for_card_timeout = 5
- debug_level = 10
-
- [domain/auth_only]
- debug_level = 10
- {provider.p}
-
- [certmap/auth_only/abc]
- matchrule = .*CN=SSSD test cert 000[12].*
- maprule = LDAPU1:(user1)
- """).format(**locals())
-
-
-def format_pam_cert_auth_conf_name_format(config, provider):
- """Format SSSD configuration with full_name_format"""
- return unindent("""\
- [sssd]
- debug_level = 10
- domains = auth_only
- services = pam, nss
-
- [nss]
- debug_level = 10
-
- [pam]
- pam_cert_auth = True
- pam_p11_allowed_services = +pam_sss_service, +pam_sss_sc_required, \
- +pam_sss_try_sc, +pam_sss_allow_missing_name
- pam_cert_db_path = {config.PAM_CERT_DB_PATH}
- p11_uri = pkcs11:manufacturer=SoftHSM%20project; \
- token=SSSD%20Test%20Token
- p11_child_timeout = 5
- p11_wait_for_card_timeout = 5
- debug_level = 10
-
- [domain/auth_only]
- use_fully_qualified_names = True
- full_name_format = %2$s\\%1$s
- debug_level = 10
- {provider.p}
-
- [certmap/auth_only/user1]
- matchrule = .*CN=SSSD test cert 000[12].*
- """).format(**locals())
-
-
-def format_pam_krb5_auth(config, kdc_instance):
- """Format SSSD configuration for krb5 authentication"""
- return unindent("""\
- [sssd]
- debug_level = 10
- domains = krb5_auth
- services = pam, nss
-
- [nss]
- debug_level = 10
-
- [pam]
- debug_level = 10
-
- [domain/krb5_auth]
- debug_level = 10
- id_provider = proxy
- proxy_lib_name = call
- auth_provider = krb5
-
- krb5_realm = PAMKRB5TEST
- krb5_server = localhost:{kdc_instance.kdc_port}
- """).format(**locals())
-
-
-def format_pam_krb5_auth_domains(config, kdc_instance):
- """Format SSSD configuration for krb5 authentication"""
- return unindent("""\
- [sssd]
- debug_level = 10
- domains = wrong.dom1, wrong.dom2, krb5_auth, wrong.dom3
- services = pam, nss
-
- [nss]
- debug_level = 10
-
- [pam]
- debug_level = 10
-
- [domain/wrong.dom1]
- debug_level = 10
- id_provider = proxy
- proxy_lib_name = call
- auth_provider = krb5
-
- krb5_realm = WRONG1REALM
- krb5_server = localhost:{kdc_instance.kdc_port}
-
- [domain/wrong.dom2]
- debug_level = 10
- id_provider = proxy
- proxy_lib_name = call
- auth_provider = krb5
-
- krb5_realm = WRONG2REALM
- krb5_server = localhost:{kdc_instance.kdc_port}
-
- [domain/wrong.dom3]
- debug_level = 10
- id_provider = proxy
- proxy_lib_name = call
- auth_provider = krb5
-
- krb5_realm = WRONG3REALM
- krb5_server = localhost:{kdc_instance.kdc_port}
-
- [domain/krb5_auth]
- debug_level = 10
- id_provider = proxy
- proxy_lib_name = call
- auth_provider = krb5
-
- krb5_realm = PAMKRB5TEST
- krb5_server = localhost:{kdc_instance.kdc_port}
- """).format(**locals())
-
-
-def create_conf_file(contents):
- """Create sssd.conf with specified contents"""
- conf = open(config.CONF_PATH, "w")
- conf.write(contents)
- conf.close()
- os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR)
-
-
-def create_conf_fixture(request, contents):
- """
- Create sssd.conf with specified contents and add teardown for removing it
- """
- create_conf_file(contents)
-
- def cleanup_conf_file():
- """Remove sssd.conf, if it exists"""
- if os.path.lexists(config.CONF_PATH):
- os.unlink(config.CONF_PATH)
-
- request.addfinalizer(cleanup_conf_file)
-
-
-def create_sssd_process(krb5_conf_path=None):
- """Start the SSSD process"""
- my_env = os.environ.copy()
- my_env["SSS_FILES_PASSWD"] = os.environ["NSS_WRAPPER_PASSWD"]
- my_env["SSS_FILES_GROUP"] = os.environ["NSS_WRAPPER_GROUP"]
- my_env['SSSD_INTG_PEER_UID'] = "0"
- my_env['SSSD_INTG_PEER_GID'] = "0"
- if krb5_conf_path is not None:
- my_env['KRB5_CONFIG'] = krb5_conf_path
- if subprocess.call(["sssd", "-D", "--logger=files"], env=my_env) != 0:
- raise Exception("sssd start failed")
-
-
-def cleanup_sssd_process():
- """Stop the SSSD process and remove its state"""
- try:
- with open(config.PIDFILE_PATH, "r") as pid_file:
- pid = int(pid_file.read())
- os.kill(pid, signal.SIGTERM)
- while True:
- try:
- os.kill(pid, signal.SIGCONT)
- except OSError:
- break
- time.sleep(1)
- except OSError:
- pass
- for path in os.listdir(config.DB_PATH):
- os.unlink(config.DB_PATH + "/" + path)
- for path in os.listdir(config.MCACHE_PATH):
- os.unlink(config.MCACHE_PATH + "/" + path)
-
- # make sure that the indicator file is removed during shutdown
- try:
- assert not os.stat(config.PUBCONF_PATH + "/pam_preauth_available")
- except OSError as ex:
- if ex.errno != errno.ENOENT:
- raise ex
-
-
-def create_sssd_fixture(request, krb5_conf_path=None):
- """Start SSSD and add teardown for stopping it and removing its state"""
- create_sssd_process(krb5_conf_path)
- request.addfinalizer(cleanup_sssd_process)
-
-
-@pytest.fixture
-def simple_pam_cert_auth(request, passwd_ops_setup):
- """Setup SSSD with pam_cert_auth=True"""
- config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
- conf = format_pam_cert_auth_conf(config, provider_switch(request.param))
- create_conf_fixture(request, conf)
- create_sssd_fixture(request)
- passwd_ops_setup.useradd(**USER1)
- passwd_ops_setup.useradd(**USER2)
-
- return None
-
-
-@pytest.fixture
-def simple_pam_cert_auth_no_cert(request, passwd_ops_setup):
- """Setup SSSD with pam_cert_auth=True"""
- config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
-
- old_softhsm2_conf = os.environ['SOFTHSM2_CONF']
- del os.environ['SOFTHSM2_CONF']
-
- conf = format_pam_cert_auth_conf(config, provider_switch(request.param))
- create_conf_fixture(request, conf)
- create_sssd_fixture(request)
-
- os.environ['SOFTHSM2_CONF'] = old_softhsm2_conf
-
- passwd_ops_setup.useradd(**USER1)
- passwd_ops_setup.useradd(**USER2)
-
- return None
-
-
-@pytest.fixture
-def simple_pam_cert_auth_two_certs(request, passwd_ops_setup):
- """Setup SSSD with pam_cert_auth=True"""
- config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
-
- old_softhsm2_conf = os.environ['SOFTHSM2_CONF']
- softhsm2_two_conf = os.environ['SOFTHSM2_TWO_CONF']
- os.environ['SOFTHSM2_CONF'] = softhsm2_two_conf
-
- conf = format_pam_cert_auth_conf(config, provider_switch(request.param))
- create_conf_fixture(request, conf)
- create_sssd_fixture(request)
-
- os.environ['SOFTHSM2_CONF'] = old_softhsm2_conf
-
- passwd_ops_setup.useradd(**USER1)
- passwd_ops_setup.useradd(**USER2)
-
- return None
-
-
-@pytest.fixture
-def simple_pam_cert_auth_name_format(request, passwd_ops_setup):
- """Setup SSSD with pam_cert_auth=True and full_name_format"""
- config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH']
- conf = format_pam_cert_auth_conf_name_format(config, provider_switch(request.param))
- create_conf_fixture(request, conf)
- create_sssd_fixture(request)
- passwd_ops_setup.useradd(**USER1)
- passwd_ops_setup.useradd(**USER2)
-
- return None
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_preauth_indicator(simple_pam_cert_auth):
- """Check if preauth indicator file is created"""
- statinfo = os.stat(config.PUBCONF_PATH + "/pam_preauth_available")
- assert stat.S_ISREG(statinfo.st_mode)
-
-
-@pytest.fixture
-def pam_prompting_config(request, ldap_conn):
- """Setup SSSD with PAM prompting config"""
- conf = format_basic_conf(ldap_conn)
- create_conf_fixture(request, conf)
- create_sssd_fixture(request)
- return None
-
-
-def test_password_prompting_config_global(ldap_conn, pam_prompting_config,
- env_for_sssctl):
- """Check global change of the password prompt"""
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1_dom1-19661",
- "--action=auth", "--service=pam_sss_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="111")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("My global prompt") != -1
-
-
-def test_password_prompting_config_srv(ldap_conn, pam_prompting_config,
- env_for_sssctl):
- """Check change of the password prompt for dedicated service"""
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1_dom1-19661",
- "--action=auth",
- "--service=pam_sss_alt_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="111")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("My alt service prompt") != -1
-
-
-@pytest.fixture
-def env_for_sssctl(request):
- pwrap_runtimedir = os.getenv("PAM_WRAPPER_SERVICE_DIR")
- if pwrap_runtimedir is None:
- raise ValueError("The PAM_WRAPPER_SERVICE_DIR variable is unset\n")
-
- env_for_sssctl = os.environ.copy()
- env_for_sssctl['PAM_WRAPPER'] = "1"
- env_for_sssctl['SSSD_INTG_PEER_UID'] = "0"
- env_for_sssctl['SSSD_INTG_PEER_GID'] = "0"
- env_for_sssctl['LD_PRELOAD'] += ':' + os.environ['PAM_WRAPPER_PATH']
-
- return env_for_sssctl
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_sc_auth_wrong_pin(simple_pam_cert_auth, env_for_sssctl):
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth", "--service=pam_sss_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="111")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: "
- "Authentication failure") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_sc_auth(simple_pam_cert_auth, env_for_sssctl):
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth", "--service=pam_sss_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: Success") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth_two_certs', provider_list(), indirect=True)
-def test_sc_auth_two(simple_pam_cert_auth_two_certs, env_for_sssctl):
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth", "--service=pam_sss_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="2\n123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: Success") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth_two_certs', provider_list(), indirect=True)
-def test_sc_auth_two_missing_name(simple_pam_cert_auth_two_certs, env_for_sssctl):
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "",
- "--action=auth", "--service=pam_sss_allow_missing_name"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="2\n123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: Success") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', ['proxy_password'], indirect=True)
-def test_sc_proxy_password_fallback(simple_pam_cert_auth, env_for_sssctl):
- """
- Check that there will be a password prompt if another proxy auth module is
- configured and Smartcard authentication is not allowed but a Smartcard is
- present.
- """
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth", "--service=pam_sss_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- assert err.find("Password:") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', ['proxy_password_with_sc'],
- indirect=True)
-def test_sc_proxy_no_password_fallback(simple_pam_cert_auth, env_for_sssctl):
- """
- Use the same environ as for test_sc_proxy_password_fallback but now allow
- local Smartcard authentication. Here we expect that there will be a prompt
- for the Smartcard PIN and that Smartcard authentication is successful.
- """
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth", "--service=pam_sss_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: Success") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_require_sc_auth(simple_pam_cert_auth, env_for_sssctl):
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth",
- "--service=pam_sss_sc_required"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: Success") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth_no_cert', provider_list(), indirect=True)
-def test_require_sc_auth_no_cert(simple_pam_cert_auth_no_cert, env_for_sssctl):
-
- # We have to wait about 20s before the command returns because there will
- # be 2 run since retry=1 in the PAM configuration and both
- # p11_child_timeout and p11_wait_for_card_timeout are 5s in sssd.conf,
- # so 2*(5+5)=20. */
- start_time = time.time()
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth",
- "--service=pam_sss_sc_required"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- end_time = time.time()
- assert end_time > start_time and \
- (end_time - start_time) >= 20 and \
- (end_time - start_time) < 40
- assert out.find("Please insert smart card\nPlease insert smart card") != -1
- assert err.find("pam_authenticate for user [user1]: Authentication "
- "service cannot retrieve authentication info") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_try_sc_auth_no_map(simple_pam_cert_auth, env_for_sssctl):
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user2",
- "--action=auth",
- "--service=pam_sss_try_sc"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user2]: Authentication "
- "service cannot retrieve authentication info") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_try_sc_auth(simple_pam_cert_auth, env_for_sssctl):
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth",
- "--service=pam_sss_try_sc"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: Success") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_try_sc_auth_root(simple_pam_cert_auth, env_for_sssctl):
- """
- Make sure pam_sss returns PAM_AUTHINFO_UNAVAIL even for root if
- try_cert_auth is set.
- """
- sssctl = subprocess.Popen(["sssctl", "user-checks", "root",
- "--action=auth",
- "--service=pam_sss_try_sc"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [root]: Authentication "
- "service cannot retrieve authentication info") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_sc_auth_missing_name(simple_pam_cert_auth, env_for_sssctl):
- """
- Test pam_sss allow_missing_name feature.
- """
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "",
- "--action=auth",
- "--service=pam_sss_allow_missing_name"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: Success") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth', provider_list(), indirect=True)
-def test_sc_auth_missing_name_whitespace(simple_pam_cert_auth, env_for_sssctl):
- """
- Test pam_sss allow_missing_name feature.
- """
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", " ",
- "--action=auth",
- "--service=pam_sss_allow_missing_name"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find("pam_authenticate for user [user1]: Success") != -1
-
-
-@pytest.mark.parametrize('simple_pam_cert_auth_name_format', provider_list(), indirect=True)
-def test_sc_auth_name_format(simple_pam_cert_auth_name_format, env_for_sssctl):
- """
- Test that full_name_format is respected with pam_sss allow_missing_name
- option.
- """
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "",
- "--action=auth",
- "--service=pam_sss_allow_missing_name"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="123456")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find(r"pam_authenticate for user [auth_only\user1]: "
- "Success") != -1
-
-
-@pytest.fixture
-def kdc_instance(request):
- """Kerberos server instance fixture"""
- kdc_instance = kdc.KDC(config.PREFIX, "PAMKRB5TEST")
- try:
- kdc_instance.set_up()
- kdc_instance.start_kdc()
- except Exception:
- kdc_instance.teardown()
- raise
- request.addfinalizer(kdc_instance.teardown)
- return kdc_instance
-
-
-@pytest.fixture
-def setup_krb5(request, kdc_instance, passwd_ops_setup):
- """
- Setup SSSD for Kerberos authentication with 2 users with different
- passwords
- """
- conf = format_pam_krb5_auth(config, kdc_instance)
- create_conf_fixture(request, conf)
- create_sssd_fixture(request, kdc_instance.krb5_conf_path)
-
- passwd_ops_setup.useradd(**USER1)
- passwd_ops_setup.useradd(**USER2)
- kdc_instance.add_principal("user1", "Secret123User1")
- kdc_instance.add_principal("user2", "Secret123User2")
- time.sleep(2) # Give KDC time to initialize
- return None
-
-
-def test_krb5_auth(setup_krb5, env_for_sssctl):
- """
- Test basic Kerberos authentication, check for authentication failure when
- a wrong password is used
- """
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth",
- "--service=pam_sss_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="Secret123User1")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find(r"pam_authenticate for user [user1]: Success") != -1
-
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user2",
- "--action=auth",
- "--service=pam_sss_service"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="Secret123User1")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find(r"pam_authenticate for user [user2]: "
- "Authentication failure") != -1
-
-
-@pytest.fixture
-def setup_krb5_domains(request, kdc_instance, passwd_ops_setup):
- """
- Setup SSSD for Kerberos authentication with 2 users with different
- passwords and multiple domains configured in sssd.conf
- """
- conf = format_pam_krb5_auth_domains(config, kdc_instance)
- create_conf_fixture(request, conf)
- create_sssd_fixture(request, kdc_instance.krb5_conf_path)
-
- passwd_ops_setup.useradd(**USER1)
- passwd_ops_setup.useradd(**USER2)
- kdc_instance.add_principal("user1", "Secret123User1")
- kdc_instance.add_principal("user2", "Secret123User2")
- return None
-
-
-def test_krb5_auth_domains(setup_krb5_domains, env_for_sssctl):
- """
- Test basic Kerberos authentication with pam_sss 'domains' option, make
- sure not-matching domains are skipped even if the user exists in that
- domain
- """
- sssctl = subprocess.Popen(["sssctl", "user-checks", "user1",
- "--action=auth",
- "--service=pam_sss_domains"],
- universal_newlines=True,
- env=env_for_sssctl, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-
- try:
- out, err = sssctl.communicate(input="Secret123User1")
- except Exception:
- sssctl.kill()
- out, err = sssctl.communicate()
-
- sssctl.stdin.close()
- sssctl.stdout.close()
-
- if sssctl.wait() != 0:
- raise Exception("sssctl failed")
-
- assert err.find(r"pam_authenticate for user [user1]: Success") != -1
diff --git a/src/tests/intg/util.py b/src/tests/intg/util.py
deleted file mode 100644
index 543bfe4892d..00000000000
--- a/src/tests/intg/util.py
+++ /dev/null
@@ -1,107 +0,0 @@
-#
-# Various functions
-#
-# Copyright (c) 2015 Red Hat, Inc.
-# Author: Nikolai Kondrashov
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-
-import re
-import os
-import sys
-import subprocess
-import config
-import shutil
-
-UNINDENT_RE = re.compile("^ +", re.MULTILINE)
-
-
-def unindent(text):
- """
- Unindent text by removing at most the number of spaces present in
- the first non-empty line from the beginning of every line.
- """
- indent_ref = [0]
-
- def replace(match):
- if indent_ref[0] == 0:
- indent_ref[0] = len(match.group())
- return match.group()[indent_ref[0]:]
- return UNINDENT_RE.sub(replace, text)
-
-
-def run_shell():
- """
- Execute an interactive shell under "screen", preserving environment.
- For use as a breakpoint for debugging.
- """
- my_env = os.environ.copy()
- my_env["ROOT_DIR"] = config.PREFIX
-
- # screen filter out LD_* evniroment varibles.
- # Back-up them and set them later in screenrc
- my_env["_LD_LIBRARY_PATH"] = os.getenv("LD_LIBRARY_PATH", "")
- my_env["_LD_PRELOAD"] = os.getenv("LD_PRELOAD", "")
-
- subprocess.call([
- "screen", "-DAm", "-S", "sssd_cwrap_session", "-c",
- ".config/screenrc"],
- env=my_env
- )
-
-
-def first_dir(*args):
- """Return first argument that points to an existing directory."""
- for arg in args:
- if os.path.isdir(arg):
- return arg
-
-
-def backup_envvar_file(name):
- path = os.environ[name]
- backup_path = path + ".bak"
- shutil.copyfile(path, backup_path)
- return path
-
-
-def restore_envvar_file(name):
- path = os.environ[name]
- backup_path = path + ".bak"
- os.rename(backup_path, path)
-
-
-def get_call_output(cmd, stderr_output=subprocess.PIPE, check=False, custom_env=None):
- """
- Executes the provided command.
- When check is set to True, this function will throw an exception
- if the command returns with a non-zero value.
- """
-
- if (sys.version_info.major < 3
- or (sys.version_info.major == 3 and sys.version_info.minor < 7)):
- try:
- output = subprocess.check_output(cmd, universal_newlines=True,
- stderr=stderr_output, env=custom_env)
- except subprocess.CalledProcessError as err:
- if (not check):
- output = err.output
- else:
- raise err
- return output
-
- process = subprocess.run(cmd, check=check, text=True,
- stdout=subprocess.PIPE, stderr=stderr_output,
- env=custom_env)
- return process.stdout
diff --git a/src/tests/system/tests/test_authentication.py b/src/tests/system/tests/test_authentication.py
index 277f1454184..5362039fb05 100644
--- a/src/tests/system/tests/test_authentication.py
+++ b/src/tests/system/tests/test_authentication.py
@@ -7,11 +7,15 @@
from __future__ import annotations
import re
+import textwrap
+from inspect import cleandoc
import pytest
from sssd_test_framework.roles.client import Client
from sssd_test_framework.roles.generic import GenericProvider
+from sssd_test_framework.roles.ipa import IPA
from sssd_test_framework.roles.kdc import KDC
+from sssd_test_framework.roles.samba import Samba
from sssd_test_framework.topology import KnownTopology, KnownTopologyGroup
@@ -375,3 +379,142 @@ def test_ensure_localauth_plugin_is_not_configured(client: Client, provider: Gen
with pytest.raises(Exception):
client.fs.read("/var/lib/sss/pubconf/krb5.include.d/localauth_plugin")
+
+
+@pytest.mark.importance("medium")
+@pytest.mark.topology(KnownTopologyGroup.AnyProvider)
+@pytest.mark.parametrize(
+ "prompting_section",
+ ["prompting/password", "prompting/password/su-l"],
+ ids=["global_prompt", "service_prompt"],
+)
+def test_authentication__custom_password_prompt_is_shown_at_login(
+ client: Client, provider: GenericProvider, prompting_section: str
+):
+ """
+ :title: Custom password prompt text is shown at login
+ :description:
+ 'su -' uses the 'su-l' PAM service, so the per-service case targets
+ '[prompting/password/su-l]', not '[prompting/password/su]'.
+ :setup:
+ 1. Create user
+ 2. Set a custom 'password_prompt', either globally or for the 'su -' PAM service ('su-l')
+ 3. Start SSSD
+ :steps:
+ 1. Authenticate as the user via 'su -'
+ :expectedresults:
+ 1. The custom prompt text is shown and authentication succeeds
+ :customerscenario: True
+ """
+ provider.user("user1").add(password="Secret123")
+ client.sssd.section(prompting_section)["password_prompt"] = "My custom prompt"
+ client.sssd.start()
+
+ result = client.host.conn.run("su - user1 -c 'su - user1 -c whoami'", input="Secret123")
+ assert "My custom prompt" in result.stderr, "Custom password prompt was not shown!"
+ assert "user1" in result.stdout, "'user1' failed to log in!"
+
+
+@pytest.mark.importance("medium")
+@pytest.mark.authentication
+@pytest.mark.topology(KnownTopology.ALLREALMS)
+def test_authentication__pam_sss_domains_skips_non_matching_krb5_domains(
+ client: Client, samba: Samba, ipa: IPA, kdc: KDC
+):
+ """
+ :title: pam_sss.so 'domains' authenticates only against the listed Kerberos realm domain
+ :description:
+ Local users may authenticate via Kerberos against one of several configured realms
+ (Samba, IPA, or a standalone KDC). The same username exists in every realm with a
+ different password. Each PAM 'domains=' line restricts SSSD to that domain only, so
+ earlier lines fail with the wrong password and PAM falls through until the matching
+ domain succeeds (try-and-error via the domains option).
+ :setup:
+ 1. Add a local user and create 'user1' in the Samba, IPA, and KDC realms with
+ different passwords
+ 2. Configure three SSSD domains (samba, ipa, krb5) with id_provider=proxy/files and
+ auth_provider=krb5 using each provider's realm
+ 3. Replace 'su-l' with three 'sufficient' pam_sss.so lines, each limited by 'domains='
+ :steps:
+ 1. Authenticate as the local user via 'su -' using the Samba password and run klist
+ 2. Authenticate as the local user via 'su -' using the IPA password and run klist
+ 3. Authenticate as the local user via 'su -' using the KDC password and run klist
+ :expectedresults:
+ 1. Authentication succeeds via 'domains=samba' and the TGT realm is the Samba realm
+ 2. Authentication succeeds via 'domains=ipa' (after Samba fails) and the TGT realm is
+ the IPA realm
+ 3. Authentication succeeds via 'domains=krb5' (after Samba and IPA fail) and the TGT
+ realm is the KDC realm
+ :customerscenario: True
+ """
+ client.local.user("user1").add(password="LocalSecret123")
+ samba.user("user1").add(password="SambaSecret123")
+ ipa.user("user1").add(password="IPASecret123")
+ kdc.principal("user1").add(password="KDCSecret123")
+
+ client.sssd.fs.write(
+ "/etc/krb5.conf",
+ textwrap.dedent(f"""
+ [libdefaults]
+ default_realm = {kdc.realm}
+ dns_lookup_realm = false
+ dns_lookup_kdc = false
+ ticket_lifetime = 24h
+ renew_lifetime = 7d
+ forwardable = yes
+
+ [realms]
+ {samba.realm} = {{
+ kdc = {samba.host.hostname}
+ }}
+ {ipa.realm} = {{
+ kdc = {ipa.host.hostname}
+ }}
+ {kdc.realm} = {{
+ kdc = {kdc.host.hostname}:88
+ admin_server = {kdc.host.hostname}:749
+ }}
+ """).lstrip(),
+ user="root",
+ group="root",
+ mode="0644",
+ )
+
+ for name, role in (("samba", samba), ("ipa", ipa), ("krb5", kdc)):
+ client.sssd.dom(name).update(
+ enabled="true",
+ id_provider="proxy",
+ proxy_lib_name="files",
+ auth_provider="krb5",
+ krb5_realm=role.realm,
+ krb5_server=role.host.hostname,
+ )
+ client.sssd.sssd["domains"] = "samba, ipa, krb5"
+ client.sssd.default_domain = "krb5"
+ client.sssd.start()
+
+ client.fs.backup("/etc/pam.d/su-l")
+ client.fs.write(
+ "/etc/pam.d/su-l",
+ cleandoc("""
+ auth required pam_env.so
+ auth sufficient pam_sss.so forward_pass domains=samba
+ auth sufficient pam_sss.so forward_pass domains=ipa
+ auth sufficient pam_sss.so forward_pass domains=krb5
+ auth required pam_deny.so
+ account required pam_sss.so
+ password required pam_sss.so
+ session required pam_sss.so
+ """),
+ )
+
+ for password, realm, domain in (
+ ("SambaSecret123", samba.realm, "samba"),
+ ("IPASecret123", ipa.realm, "ipa"),
+ ("KDCSecret123", kdc.realm, "krb5"),
+ ):
+ result = client.host.conn.run("su - user1 -c klist", input=password, raise_on_error=False)
+ assert result.rc == 0, f"Authentication with the {domain} password failed!"
+ assert (
+ f"krbtgt/{realm}@{realm}" in result.stdout
+ ), f"TGT should come from the {domain} realm ({realm}) when authenticating with that realm's password!"
diff --git a/src/tests/system/tests/test_smartcard.py b/src/tests/system/tests/test_smartcard.py
index 2d7f7e5f60d..41b3fac94a7 100644
--- a/src/tests/system/tests/test_smartcard.py
+++ b/src/tests/system/tests/test_smartcard.py
@@ -7,7 +7,6 @@
from __future__ import annotations
import pytest
-from pytest_mh.cli import CLIBuilderArgs
from sssd_test_framework.roles.client import Client
from sssd_test_framework.roles.ipa import IPA
from sssd_test_framework.topology import KnownTopology
@@ -337,60 +336,367 @@ def test_smartcard__unlock_console_with_vlock(client: Client):
client.local.user(username).add()
client.smartcard.setup_local_card(client, username)
- cli = client.host.cli
- args: CLIBuilderArgs = {
- "login": (cli.option.SWITCH, True),
- "user": (cli.option.POSITIONAL, username),
- }
- su_cmd = " ".join(cli.argv("su", args))
-
- result = client.host.conn.expect(
- rf"""
- proc exitmsg {{ msg code }} {{
- catch close
- lassign [wait] pid spawnid os_error_flag rc
- puts ""
- puts "expect result: $msg"
- puts "expect exit code: $code"
- puts "expect spawn exit code: $rc"
- exit $code
- }}
-
- set timeout 60
- spawn {su_cmd}
-
- expect {{
- "$ " {{ }}
- timeout {{exitmsg "No shell prompt after su" 201}}
- eof {{exitmsg "Unexpected end of file after su" 202}}
- }}
-
- send "vlock\r"
-
- expect {{
- "PIN for" {{send "wrongpin\r"}}
- timeout {{exitmsg "No PIN prompt from vlock" 201}}
- eof {{exitmsg "Unexpected end of file during vlock" 202}}
- }}
-
- expect {{
- "PIN for" {{send "{TOKEN_PIN}\r"}}
- "$ " {{exitmsg "vlock unlocked with wrong PIN" 1}}
- timeout {{exitmsg "No re-prompt after wrong PIN" 201}}
- eof {{exitmsg "Unexpected end of file after wrong PIN" 202}}
- }}
-
- expect {{
- "$ " {{exitmsg "vlock unlock successful" 0}}
- timeout {{exitmsg "Timeout after vlock unlock" 201}}
- eof {{exitmsg "Unexpected end of file after vlock" 202}}
- }}
-
- exitmsg "Unexpected code path" 203
+ assert client.auth.su.vlock_smartcard(username, TOKEN_PIN), "vlock smartcard authentication failed"
+
+
+@pytest.mark.importance("high")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.builtwith(client="virtualsmartcard")
+def test_smartcard__login_fails_when_wrong_pin_is_entered(client: Client):
+ """
+ :title: Smartcard login fails when the wrong pin is entered.
+ :setup:
+ 1. Create a local user and initialize a smart card mapped to the user
+ :steps:
+ 1. Authenticate as the user via 'su' with an incorrect PIN
+ :expectedresults:
+ 1. Authentication fails
+ :customerscenario: True
+ """
+ client.local.user("user1").add()
+ client.smartcard.setup_local_card(client, "user1")
+
+ assert not client.auth.su.smartcard("user1", "000000"), "Authentication should have failed with a wrong PIN!"
+
+
+@pytest.mark.importance("medium")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.builtwith(client="virtualsmartcard")
+def test_smartcard__login_fails_when_card_is_not_mapped(client: Client):
+ """
+ :title: Smartcard authentication fails when card is not mapped to the user
+ :setup:
+ 1. Create two local users and initialize a smart card mapped to only the first user
+ :steps:
+ 1. Authenticate as the first user via 'su' with the smart card PIN
+ 2. Attempt to authenticate as the second user via 'su' with the same smart card PIN
+ :expectedresults:
+ 1. Authentication succeeds using the certificate
+ 2. Authentication fails because the certificate does not map to the second user
+ :customerscenario: True
+ """
+ client.local.user("user1").add()
+ client.local.user("user2").add()
+ client.smartcard.setup_local_card(client, "user1")
+
+ assert client.auth.su.smartcard("user1", TOKEN_PIN), "Smart card authentication failed for the mapped user!"
+ assert not client.auth.su.smartcard(
+ "user2", TOKEN_PIN
+ ), "Authentication should fail for a user the certificate does not map to!"
+
+
+@pytest.mark.importance("high")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.parametrize(
+ "pam_p11_allowed_services, expect_cert_auth",
+ [(None, True), ("-su-l", False)],
+ ids=["su_l_allowed_by_default", "su_l_removed_from_allowed_services"],
+)
+@pytest.mark.builtwith(client="virtualsmartcard")
+def test_smartcard__certificate_authentication_is_limited_to_allowed_pam_services(
+ client: Client, pam_p11_allowed_services: str | None, expect_cert_auth: bool
+):
+ """
+ :title: Smartcard authentication is only used for PAM services allowed by pam_p11_allowed_services
+ :setup:
+ 1. Optionally remove the 'su-l' service (used by ``su -``) from 'pam_p11_allowed_services'
+ 2. Create a local user and initialize a smart card mapped to the user
+ :steps:
+ 1. Authenticate as the user via 'su -' presenting the smart card PIN
+ :expectedresults:
+ 1. Authentication uses the certificate when 'su-l' is an allowed service; when it is not,
+ 'su -' does not prompt for a PIN and the PIN is rejected as a regular password
+ :customerscenario: True
+ """
+ client.local.user("user1").add()
+ if pam_p11_allowed_services is not None:
+ client.sssd.pam["pam_p11_allowed_services"] = pam_p11_allowed_services
+ client.smartcard.setup_local_card(client, "user1")
+
+ result = client.auth.su.smartcard_with_output("user1", TOKEN_PIN)
+ if expect_cert_auth:
+ assert result.rc == 0, "Smart card authentication should have succeeded!"
+ assert "PIN" in result.stderr, "'su -' should have prompted for a PIN!"
+ else:
+ assert "PIN" not in result.stderr, "'su -' should not prompt for a PIN when it is not an allowed service!"
+ assert result.rc != 0, f"'{TOKEN_PIN}' should not be accepted as user1's login password!"
+
+
+@pytest.mark.importance("high")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.builtwith(client="virtualsmartcard")
+def test_smartcard__login_succeeds_when_cert_auth_required(client: Client):
+ """
+ :title: Smartcard login succeeds when certificate authentication is required
+ :setup:
+ 1. Create a local user and initialize a smart card mapped to the user
+ 2. Require certificate-based authentication (authselect 'with-smartcard-required')
+ :steps:
+ 1. Authenticate as the user via ``sssctl user-checks`` with the ``login`` PAM
+ service and the smart card PIN
+ :expectedresults:
+ 1. Authentication succeeds
+ :customerscenario: True
+ """
+ client.local.user("user1").add()
+ client.smartcard.setup_local_card(client, "user1")
+ client.authselect.select("sssd", ["with-smartcard-required"])
+
+ result = client.sssctl.user_checks("user1", action="auth", service="login", auth_input=TOKEN_PIN)
+ assert "pam_authenticate for user [user1]: Success" in result.stderr
+
+
+@pytest.mark.importance("medium")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.builtwith(client="virtualsmartcard")
+def test_smartcard__login_fails_when_cert_auth_required_without_card(client: Client):
+ """
+ :title: Smartcard login fails when certificate authentication is required and no card is present
+ :setup:
+ 1. Create a local user
+ 2. Reduce the smart card wait timeouts
+ 3. Initialize a smart card mapped to the user and require certificate-based
+ authentication (authselect 'with-smartcard-required')
+ 4. Remove the smart card
+ :steps:
+ 1. Attempt to authenticate as the user via ``sssctl user-checks`` with the
+ ``login`` PAM service
+ :expectedresults:
+ 1. Authentication fails because no smart card was inserted before the timeout
+ :customerscenario: True
+ """
+ client.local.user("user1").add()
+ client.sssd.pam["p11_child_timeout"] = "1"
+ client.sssd.pam["p11_wait_for_card_timeout"] = "1"
+ client.smartcard.setup_local_card(client, "user1")
+ client.authselect.select("sssd", ["with-smartcard-required"])
+ client.smartcard.remove_card()
+
+ result = client.sssctl.user_checks("user1", action="auth", service="login", auth_input=TOKEN_PIN)
+ assert (
+ "Authentication service cannot retrieve authentication info" in result.stderr
+ ), "Authentication should have failed without a card!"
+
+
+@pytest.mark.importance("critical")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.builtwith(client="virtualsmartcard")
+def test_smartcard__try_cert_auth_never_used_for_root(client: Client):
+ """
+ :title: try_cert_auth never routes root's own login through certificate authentication
+ :description:
+ pam_sss.so unconditionally refuses to handle the 'root' identity. When 'try_cert_auth'
+ is set, that refusal must surface as PAM_AUTHINFO_UNAVAIL (so the PAM stack falls back
+ to another module), not as a successful or user-unknown result. This is verified via
+ 'sssctl user-checks' against a minimal 'auth required pam_sss.so try_cert_auth' service,
+ since there is no way to originate a fresh authentication attempt for the 'root' identity
+ itself via 'su'/'ssh' (root already owns the control connection).
+ :setup:
+ 1. Create a local user and initialize a smart card mapped to the user
+ 2. Install a minimal PAM service with 'pam_sss.so try_cert_auth'
+ :steps:
+ 1. Run 'sssctl user-checks root' against that service
+ :expectedresults:
+ 1. Authentication is reported unavailable, never routed through certificate auth
+ :customerscenario: True
+ """
+ client.local.user("user1").add()
+ client.smartcard.setup_local_card(client, "user1")
+ client.fs.write(
+ "/etc/pam.d/pam_sss_try_sc",
+ """
+ auth required pam_sss.so try_cert_auth
+ account required pam_sss.so
+ password required pam_sss.so
+ session required pam_sss.so
""",
- verbose=False,
)
+ result = client.sssctl.user_checks("root", action="auth", service="pam_sss_try_sc", auth_input=TOKEN_PIN)
+ assert (
+ "pam_authenticate for user [root]: Authentication service cannot retrieve authentication info" in result.stderr
+ ), f"root should never be routed through certificate authentication! stderr={result.stderr}"
+
+
+@pytest.mark.importance("high")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.parametrize("username_input", ["", " "], ids=["empty_name", "whitespace_only_name"])
+@pytest.mark.builtwith(client="virtualsmartcard")
+def test_smartcard__certificate_owner_resolved_when_username_is_missing(client: Client, username_input: str):
+ """
+ :title: allow_missing_name resolves the certificate owner when no username is given
+ :setup:
+ 1. Create a local user and initialize a smart card mapped to the user
+ :steps:
+ 1. Authenticate against the 'smartcard-auth' service with an empty or
+ whitespace-only username and the smart card PIN
+ :expectedresults:
+ 1. Authentication succeeds and is resolved to the certificate's mapped user
+ :customerscenario: True
+ """
+ client.local.user("user1").add()
+ client.smartcard.setup_local_card(client, "user1")
+ client.authselect.select("sssd", ["with-smartcard-required"])
+ client.sssd.pam["pam_p11_allowed_services"] = "+smartcard-auth"
+ client.sssd.restart()
+
+ result = client.sssctl.user_checks(username_input, action="auth", service="smartcard-auth", auth_input=TOKEN_PIN)
+ assert (
+ "pam_authenticate for user [user1]: Success" in result.stderr
+ ), f"Certificate owner was not resolved! stderr={result.stderr}"
+
+
+@pytest.mark.importance("medium")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.builtwith(client="virtualsmartcard")
+def test_smartcard__certificate_owner_resolved_with_full_name_format(client: Client):
+ """
+ :title: allow_missing_name respects full_name_format when resolving the certificate owner
+ :setup:
+ 1. Create a local user and initialize a smart card mapped to the user
+ 2. Enable fully-qualified names with a custom 'full_name_format'
+ :steps:
+ 1. Authenticate against the 'smartcard-auth' service with no username and the smart card PIN
+ :expectedresults:
+ 1. Authentication succeeds and the resolved user name matches 'full_name_format'
+ :customerscenario: True
+ """
+ client.local.user("user1").add()
+ client.smartcard.setup_local_card(client, "user1")
+ client.authselect.select("sssd", ["with-smartcard-required"])
+ client.sssd.pam["pam_p11_allowed_services"] = "+smartcard-auth"
+ client.sssd.domain["use_fully_qualified_names"] = "True"
+ client.sssd.domain["full_name_format"] = "%2$s\\%1$s"
+ client.sssd.restart(clean=True)
+
+ result = client.sssctl.user_checks("", action="auth", service="smartcard-auth", auth_input=TOKEN_PIN)
assert (
- result.rc == 0
- ), f"vlock smartcard authentication failed: rc={result.rc}, stdout={result.stdout}, stderr={result.stderr}"
+ "pam_authenticate for user [local\\user1]: Success" in result.stderr
+ ), f"Certificate owner was not resolved with full_name_format applied! stderr={result.stderr}"
+
+
+@pytest.mark.importance("medium")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.parametrize("cert_selection", [1, 2])
+def test_smartcard__certificate_owner_resolved_with_two_tokens_and_missing_name(client: Client, cert_selection: int):
+ """
+ :title: allow_missing_name resolves the certificate owner when two tokens are present
+ :setup:
+ 1. Create a local user
+ 2. Reset the certificate CA trust store to a clean state
+ 3. Initialize two SoftHSM tokens, each holding a certificate mapped to the user,
+ and trust both certificates in the CA trust store
+ 4. Configure SSSD for smart card authentication and start services
+ :steps:
+ 1. Authenticate against the 'smartcard-auth' service with no username, selecting
+ each certificate in turn
+ :expectedresults:
+ 1. Authentication succeeds and is resolved to the certificate's mapped user for
+ either certificate selection
+ :customerscenario: True
+ """
+ username = "user1"
+ client.local.user(username).add()
+ client.host.fs.rm("/etc/sssd/pki/sssd_auth_ca_db.pem")
+
+ key1, cert1 = client.smartcard.generate_cert(key_path="/tmp/sc_token1.key", cert_path="/tmp/sc_token1.crt")
+ client.smartcard.initialize_card(label=TOKEN1_LABEL, user_pin=TOKEN_PIN, reset=True)
+ client.smartcard.add_key(key1, token_label=TOKEN1_LABEL, label=username)
+ client.smartcard.add_cert(cert1, token_label=TOKEN1_LABEL, label=username)
+ key2, cert2 = client.smartcard.generate_cert(key_path="/tmp/sc_token2.key", cert_path="/tmp/sc_token2.crt")
+ client.smartcard.initialize_card(label=TOKEN2_LABEL, user_pin=TOKEN_PIN, reset=False)
+ client.smartcard.add_key(key2, token_label=TOKEN2_LABEL, label=username)
+ client.smartcard.add_cert(cert2, token_label=TOKEN2_LABEL, label=username)
+
+ client.sssd.common.local()
+ client.sssd.section(f"certmap/local/{username}")["matchrule"] = ".*CN=Test Cert.*"
+ client.sssd.pam["pam_cert_auth"] = "True"
+ for cert in (cert1, cert2):
+ # dedent=False is required here: fs.append() strips trailing whitespace,
+ # by default which will corrupt the CA bundle.
+ client.host.fs.append(
+ "/etc/sssd/pki/sssd_auth_ca_db.pem", client.host.fs.read(cert).strip() + "\n", dedent=False
+ )
+ client.sssd.common.smartcard_with_softhsm(client.smartcard)
+ client.authselect.select("sssd", ["with-smartcard-required", "with-mkhomedir"])
+ client.sssd.pam["pam_p11_allowed_services"] = "+smartcard-auth"
+ client.sssd.restart()
+
+ result = client.sssctl.user_checks(
+ "", action="auth", service="smartcard-auth", auth_input=f"{cert_selection}\n{TOKEN_PIN}"
+ )
+ assert (
+ f"pam_authenticate for user [{username}]: Success" in result.stderr
+ ), f"Certificate owner was not resolved! stderr={result.stderr}"
+
+
+@pytest.mark.importance("high")
+@pytest.mark.topology(KnownTopology.Client)
+@pytest.mark.builtwith(client="virtualsmartcard")
+@pytest.mark.parametrize(
+ "local_auth_policy, auth_input, expected",
+ [
+ (None, None, "Password:"),
+ ("enable:smartcard", TOKEN_PIN, "pam_authenticate for user [user1]: Success"),
+ ],
+ ids=["password_fallback_when_smartcard_not_enabled", "smartcard_when_local_auth_policy_enables_it"],
+)
+def test_smartcard__proxy_auth_uses_password_or_smartcard_based_on_local_auth_policy(
+ client: Client, local_auth_policy: str | None, auth_input: str | None, expected: str
+):
+ """
+ :title: Proxy domain falls back to password unless local smartcard auth is enabled
+ :description:
+ With a smart card present, a proxy domain only offers password auth by default
+ (``local_auth_policy`` match). Enabling ``enable:smartcard`` switches the prompt
+ to the smart card PIN and authenticates with the certificate.
+ :setup:
+ 1. Create a local user with a password
+ 2. Enroll a smart card certificate mapped to the user
+ 3. Install a minimal PAM service that only stacks ``pam_sss.so``
+ :steps:
+ 1. Configure a proxy/files domain with ``pam_cert_auth`` and the parametrized
+ ``local_auth_policy``, then start SSSD
+ 2. Authenticate via ``sssctl user-checks`` against that PAM service
+ :expectedresults:
+ 1. SSSD starts with the requested local authentication policy
+ 2. Without smartcard enabled a password prompt is shown; with
+ ``enable:smartcard`` authentication succeeds with the PIN
+ :customerscenario: True
+ :requirement: smartcard_authentication
+ """
+ client.local.user("user1").add(password="Secret123")
+
+ client.host.fs.rm("/etc/sssd/pki/sssd_auth_ca_db.pem")
+ key, cert = client.smartcard.generate_cert()
+ client.smartcard.initialize_card()
+ client.smartcard.add_key(key)
+ client.smartcard.add_cert(cert)
+ client.authselect.select("sssd", ["with-smartcard"])
+ client.svc.restart("virt_cacard.service")
+
+ client.fs.write(
+ "/etc/pam.d/pam_sss_service",
+ """
+ auth required pam_sss.so
+ account required pam_sss.so
+ password required pam_sss.so
+ session required pam_sss.so
+ """,
+ )
+
+ client.sssd.common.local()
+ if local_auth_policy is not None:
+ client.sssd.dom("local")["local_auth_policy"] = local_auth_policy
+ client.sssd.section("certmap/local/user1")["matchrule"] = ".*CN=Test Cert.*"
+ client.sssd.pam["pam_cert_auth"] = "True"
+ client.sssd.pam["pam_p11_allowed_services"] = "+pam_sss_service"
+ client.host.fs.append("/etc/sssd/pki/sssd_auth_ca_db.pem", client.host.fs.read(cert), dedent=False)
+ client.sssd.start()
+
+ result = client.host.conn.exec(
+ ["sssctl", "user-checks", "user1", "-a", "auth", "-s", "pam_sss_service"],
+ input=auth_input,
+ raise_on_error=False,
+ )
+ assert expected in result.stderr, f"Unexpected authentication prompt or result! stderr={result.stderr}"
diff --git a/src/tests/test_CA/SSSD_test_cert_0001.config b/src/tests/test_CA/SSSD_test_cert_0001.config
index d59023ca665..ce593ae5ea1 100644
--- a/src/tests/test_CA/SSSD_test_cert_0001.config
+++ b/src/tests/test_CA/SSSD_test_cert_0001.config
@@ -1,7 +1,6 @@
# This certificate is used in
# - src/tests/cmocka/test_cert_utils.c
# - src/tests/cmocka/test_pam_srv.c
-# - src/tests/intg/test_infopipe.py
[ req ]
distinguished_name = req_distinguished_name
prompt = no