summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin M. Forbes <jforbes@fedoraproject.org>2020-10-12 08:20:43 -0500
committerJustin M. Forbes <jforbes@fedoraproject.org>2020-10-12 08:20:43 -0500
commitaa6d9438d030fa4682d5d450481085c901503da5 (patch)
tree42e5a60a9f9846e8fbefb4ad57e7b11529bdf52d
parentbecc6a87e313eeca9c7f7a2618e3d4c107f6bd74 (diff)
downloadkernel-aa6d9438d030fa4682d5d450481085c901503da5.tar.gz
kernel-aa6d9438d030fa4682d5d450481085c901503da5.tar.xz
kernel-aa6d9438d030fa4682d5d450481085c901503da5.zip
kernel-5.9.0-35
* Mon Oct 12 2020 Fedora Kernel Team <kernel-team@fedoraproject.org> [5.9.0-35] - Filter out LTO build options from the perl ccopts ("Justin M. Forbes") - Temporarily remove cdomain from sphinx documentation ("Justin M. Forbes") - Work around for gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96377 ("Justin M. Forbes") Resolves: rhbz# Signed-off-by: Justin M. Forbes <jforbes@fedoraproject.org>
-rw-r--r--Makefile.rhelver2
-rw-r--r--Patchlist.changelog12
-rwxr-xr-xgenerate_all_configs.sh20
-rw-r--r--kernel-aarch64-debug-rhel.config1
-rw-r--r--kernel-aarch64-rhel.config1
-rw-r--r--kernel-i686-debug-fedora.config1
-rw-r--r--kernel-i686-fedora.config1
-rw-r--r--kernel-ppc64le-debug-fedora.config1
-rw-r--r--kernel-ppc64le-debug-rhel.config1
-rw-r--r--kernel-ppc64le-fedora.config1
-rw-r--r--kernel-ppc64le-rhel.config1
-rw-r--r--kernel-s390x-debug-fedora.config1
-rw-r--r--kernel-s390x-debug-rhel.config1
-rw-r--r--kernel-s390x-fedora.config1
-rw-r--r--kernel-s390x-rhel.config1
-rw-r--r--kernel-s390x-zfcpdump-rhel.config1
-rw-r--r--kernel-x86_64-debug-fedora.config1
-rw-r--r--kernel-x86_64-debug-rhel.config1
-rw-r--r--kernel-x86_64-fedora.config1
-rw-r--r--kernel-x86_64-rhel.config1
-rw-r--r--kernel.spec37
-rw-r--r--patch-5.9.0-redhat.patch2
-rwxr-xr-xprocess_configs.sh75
-rw-r--r--sources6
24 files changed, 103 insertions, 68 deletions
diff --git a/Makefile.rhelver b/Makefile.rhelver
index 28ddeb911..83e59c409 100644
--- a/Makefile.rhelver
+++ b/Makefile.rhelver
@@ -12,7 +12,7 @@ RHEL_MINOR = 99
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
-RHEL_RELEASE = 32
+RHEL_RELEASE = 36
#
# Early y+1 numbering
diff --git a/Patchlist.changelog b/Patchlist.changelog
index c737ba647..b0377fca4 100644
--- a/Patchlist.changelog
+++ b/Patchlist.changelog
@@ -1,11 +1,11 @@
-https://gitlab.com/cki-project/kernel-ark/-/commit/d004487d01c8ddb49d87c553729e6043d245adb6
- d004487d01c8ddb49d87c553729e6043d245adb6 Filter out LTO build options from the perl ccopts
+https://gitlab.com/cki-project/kernel-ark/-/commit/0e4d28c89a6003100560bd30995f88e11a78dde9
+ 0e4d28c89a6003100560bd30995f88e11a78dde9 Filter out LTO build options from the perl ccopts
-https://gitlab.com/cki-project/kernel-ark/-/commit/d80b8dc4c0083e20f3c0caebfbd2bf1ab7ccf7c4
- d80b8dc4c0083e20f3c0caebfbd2bf1ab7ccf7c4 Temporarily remove cdomain from sphinx documentation
+https://gitlab.com/cki-project/kernel-ark/-/commit/f648e05a607bdceac423c8f6d14736c99543cd83
+ f648e05a607bdceac423c8f6d14736c99543cd83 Temporarily remove cdomain from sphinx documentation
-https://gitlab.com/cki-project/kernel-ark/-/commit/d6d706eab459fa9906ded320563c154dbf082a50
- d6d706eab459fa9906ded320563c154dbf082a50 Work around for gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96377
+https://gitlab.com/cki-project/kernel-ark/-/commit/187c2541d22a64db262d5415441fb8e4a6014282
+ 187c2541d22a64db262d5415441fb8e4a6014282 Work around for gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96377
https://gitlab.com/cki-project/kernel-ark/-/commit/17b0f7f1d49df30661b517d668715ff5ee1bab09
17b0f7f1d49df30661b517d668715ff5ee1bab09 Fixes "acpi: prefer booting with ACPI over DTS" to be RHEL only
diff --git a/generate_all_configs.sh b/generate_all_configs.sh
index 969ecaa96..9e3d5ecb7 100755
--- a/generate_all_configs.sh
+++ b/generate_all_configs.sh
@@ -9,7 +9,7 @@
PRIMARY=$1
DEBUGBUILDSENABLED=$2
-if [ -z $2 ]; then
+if [ -z "$2" ]; then
exit 1
fi
@@ -17,24 +17,24 @@ if [ -z "$PRIMARY" ]; then
PRIMARY=rhel
fi
-if [ "$PRIMARY" == "fedora" ]; then
+if [ "$PRIMARY" = "fedora" ]; then
SECONDARY=rhel
else
SECONDARY=fedora
fi
-for i in kernel-*-$PRIMARY.config; do
- NEW=kernel-$VERSION-`echo $i | cut -d - -f2- | sed s/-$PRIMARY//`
+for i in kernel-*-"$PRIMARY".config; do
+ NEW=kernel-"$VERSION"-$(echo "$i" | cut -d - -f2- | sed s/-"$PRIMARY"//)
#echo $NEW
- mv $i $NEW
+ mv "$i" "$NEW"
done
-rm -f kernel-*-$SECONDARY.config
+rm -f kernel-*-"$SECONDARY".config
-if [ $DEBUGBUILDSENABLED -eq 0 ]; then
+if [ "$DEBUGBUILDSENABLED" -eq 0 ]; then
for i in kernel-*debug*.config; do
- base=`echo $i | sed -r s/-?debug//g`
- NEW=kernel-`echo $base | cut -d - -f2-`
- mv $i $NEW
+ base=$(echo "$i" | sed -r s/-?debug//g)
+ NEW=kernel-$(echo "$base" | cut -d - -f2-)
+ mv "$i" "$NEW"
done
fi
diff --git a/kernel-aarch64-debug-rhel.config b/kernel-aarch64-debug-rhel.config
index 8e3ef8e07..0fb469879 100644
--- a/kernel-aarch64-debug-rhel.config
+++ b/kernel-aarch64-debug-rhel.config
@@ -1537,6 +1537,7 @@ CONFIG_FAULT_INJECTION=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-aarch64-rhel.config b/kernel-aarch64-rhel.config
index bfe28237c..8b10d935d 100644
--- a/kernel-aarch64-rhel.config
+++ b/kernel-aarch64-rhel.config
@@ -1521,6 +1521,7 @@ CONFIG_FAT_FS=m
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-i686-debug-fedora.config b/kernel-i686-debug-fedora.config
index fcc65c0f1..8ec5ff04e 100644
--- a/kernel-i686-debug-fedora.config
+++ b/kernel-i686-debug-fedora.config
@@ -1708,6 +1708,7 @@ CONFIG_FAULT_INJECTION=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-i686-fedora.config b/kernel-i686-fedora.config
index 3c2519df3..4cda9c040 100644
--- a/kernel-i686-fedora.config
+++ b/kernel-i686-fedora.config
@@ -1691,6 +1691,7 @@ CONFIG_FAT_FS=m
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-ppc64le-debug-fedora.config b/kernel-ppc64le-debug-fedora.config
index 7e3ec2dbf..09e15f6c7 100644
--- a/kernel-ppc64le-debug-fedora.config
+++ b/kernel-ppc64le-debug-fedora.config
@@ -1563,6 +1563,7 @@ CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_FAULT_INJECTION=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-ppc64le-debug-rhel.config b/kernel-ppc64le-debug-rhel.config
index 23e0b1436..b9706c4ed 100644
--- a/kernel-ppc64le-debug-rhel.config
+++ b/kernel-ppc64le-debug-rhel.config
@@ -1410,6 +1410,7 @@ CONFIG_FAULT_INJECTION=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-ppc64le-fedora.config b/kernel-ppc64le-fedora.config
index 05e415adf..e18f82ba6 100644
--- a/kernel-ppc64le-fedora.config
+++ b/kernel-ppc64le-fedora.config
@@ -1546,6 +1546,7 @@ CONFIG_FAT_FS=m
# CONFIG_FAULT_INJECTION is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-ppc64le-rhel.config b/kernel-ppc64le-rhel.config
index 8d8e74376..e266cd435 100644
--- a/kernel-ppc64le-rhel.config
+++ b/kernel-ppc64le-rhel.config
@@ -1394,6 +1394,7 @@ CONFIG_FAT_FS=m
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-s390x-debug-fedora.config b/kernel-s390x-debug-fedora.config
index 7734d43ee..6ca515b9f 100644
--- a/kernel-s390x-debug-fedora.config
+++ b/kernel-s390x-debug-fedora.config
@@ -1568,6 +1568,7 @@ CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y
CONFIG_FAULT_INJECTION=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-s390x-debug-rhel.config b/kernel-s390x-debug-rhel.config
index 2efd74650..2a18adcc5 100644
--- a/kernel-s390x-debug-rhel.config
+++ b/kernel-s390x-debug-rhel.config
@@ -1413,6 +1413,7 @@ CONFIG_FAULT_INJECTION=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-s390x-fedora.config b/kernel-s390x-fedora.config
index e6531ad5b..6ee8bd49d 100644
--- a/kernel-s390x-fedora.config
+++ b/kernel-s390x-fedora.config
@@ -1551,6 +1551,7 @@ CONFIG_FAT_FS=m
# CONFIG_FAULT_INJECTION is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-s390x-rhel.config b/kernel-s390x-rhel.config
index fdc704c64..f98532502 100644
--- a/kernel-s390x-rhel.config
+++ b/kernel-s390x-rhel.config
@@ -1397,6 +1397,7 @@ CONFIG_FAT_FS=m
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-s390x-zfcpdump-rhel.config b/kernel-s390x-zfcpdump-rhel.config
index c2a03a753..786a288c8 100644
--- a/kernel-s390x-zfcpdump-rhel.config
+++ b/kernel-s390x-zfcpdump-rhel.config
@@ -1408,6 +1408,7 @@ CONFIG_FAT_FS=m
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-x86_64-debug-fedora.config b/kernel-x86_64-debug-fedora.config
index c90ad6424..e01778721 100644
--- a/kernel-x86_64-debug-fedora.config
+++ b/kernel-x86_64-debug-fedora.config
@@ -1748,6 +1748,7 @@ CONFIG_FAULT_INJECTION=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-x86_64-debug-rhel.config b/kernel-x86_64-debug-rhel.config
index 4ff48486f..df4b4123a 100644
--- a/kernel-x86_64-debug-rhel.config
+++ b/kernel-x86_64-debug-rhel.config
@@ -1516,6 +1516,7 @@ CONFIG_FAULT_INJECTION=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-x86_64-fedora.config b/kernel-x86_64-fedora.config
index f080bcbdf..ac3d16ab1 100644
--- a/kernel-x86_64-fedora.config
+++ b/kernel-x86_64-fedora.config
@@ -1731,6 +1731,7 @@ CONFIG_FAT_FS=m
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel-x86_64-rhel.config b/kernel-x86_64-rhel.config
index f6f7b0719..f5814c5a6 100644
--- a/kernel-x86_64-rhel.config
+++ b/kernel-x86_64-rhel.config
@@ -1500,6 +1500,7 @@ CONFIG_FAT_FS=m
# CONFIG_FB_3DFX is not set
# CONFIG_FB_ARC is not set
# CONFIG_FB_ARK is not set
+# CONFIG_FB_ARMCLCD is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
diff --git a/kernel.spec b/kernel.spec
index 6e843d8cc..116786d9b 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -30,7 +30,7 @@ Summary: The Linux kernel
# For a stable, released kernel, released_kernel should be 1.
%global released_kernel 0
-%global distro_build 0.rc8.20201009git7575fdda569b.32
+%global distro_build 36
%if 0%{?fedora}
%define secure_boot_arch x86_64
@@ -69,13 +69,13 @@ Summary: The Linux kernel
%endif
%define rpmversion 5.9.0
-%define pkgrelease 0.rc8.20201009git7575fdda569b.32
+%define pkgrelease 36
# This is needed to do merge window version magic
%define patchlevel 9
# allow pkg_release to have configurable %%{?dist} tag
-%define specrelease 0.rc8.20201009git7575fdda569b.32%{?buildid}%{?dist}
+%define specrelease 36%{?buildid}%{?dist}
%define pkg_release %{specrelease}
@@ -166,7 +166,7 @@ Summary: The Linux kernel
# Set debugbuildsenabled to 1 for production (build separate debug kernels)
# and 0 for rawhide (all kernels are debug kernels).
# See also 'make debug' and 'make release'.
-%define debugbuildsenabled 0
+%define debugbuildsenabled 1
# The kernel tarball/base version
%define kversion 5.9
@@ -182,10 +182,10 @@ Summary: The Linux kernel
# no whitelist
%define with_kernel_abi_whitelists 0
# Fedora builds these separately
+%endif
%define with_perf 0
%define with_tools 0
%define with_bpftool 0
-%endif
%if %{with_verbose}
%define make_opts V=1
@@ -566,7 +566,7 @@ BuildRequires: asciidoc
# exact git commit you can run
#
# xzcat -qq ${TARBALL} | git get-tar-commit-id
-Source0: linux-20201009git7575fdda569b.tar.xz
+Source0: linux-5.9.tar.xz
Source1: Makefile.rhelver
@@ -1210,8 +1210,8 @@ ApplyOptionalPatch()
fi
}
-%setup -q -n kernel-20201009git7575fdda569b -c
-mv linux-20201009git7575fdda569b linux-%{KVERREL}
+%setup -q -n kernel-5.9 -c
+mv linux-5.9 linux-%{KVERREL}
cd linux-%{KVERREL}
cp -a %{SOURCE1} .
@@ -1923,7 +1923,6 @@ BuildKernel %make_target %kernel_image %{_use_vdso}
%global perf_make \
%{__make} -s EXTRA_CFLAGS="${RPM_OPT_FLAGS}" LDFLAGS="%{__global_ldflags}" %{?cross_opts} -C tools/perf V=1 NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 WERROR=0 NO_LIBUNWIND=1 HAVE_CPLUS_DEMANGLE=1 NO_GTK2=1 NO_STRLCPY=1 NO_BIONIC=1 prefix=%{_prefix} PYTHON=%{__python3}
%if %{with_perf}
-%global _lto_cflags %{nil}
# perf
# make sure check-headers.sh is executable
chmod +x tools/perf/check-headers.sh
@@ -2647,6 +2646,26 @@ fi
#
#
%changelog
+* Mon Oct 12 2020 Fedora Kernel Team <kernel-team@fedoraproject.org> [5.9.0-35]
+- Filter out LTO build options from the perl ccopts ("Justin M. Forbes")
+- Temporarily remove cdomain from sphinx documentation ("Justin M. Forbes")
+- Work around for gcc bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96377 ("Justin M. Forbes")
+
+* Mon Oct 12 2020 Fedora Kernel Team <kernel-team@fedoraproject.org> [5.9.0-34.test]
+- v5.9 rebase
+
+* Mon Oct 12 2020 Fedora Kernel Team <kernel-team@fedoraproject.org> [5.9.0-0.rc8.20201012gitda690031a5d6.33.test]
+- da690031a5d6 rebase
+
+* Sun Oct 11 2020 Fedora Kernel Team <kernel-team@fedoraproject.org> [5.9.0-0.rc8.20201011git6f2f486d57c4.32.test]
+- 6f2f486d57c4 rebase
+
+* Sat Oct 10 2020 Fedora Kernel Team <kernel-team@fedoraproject.org> [5.9.0-0.rc8.20201010git583090b1b823.31.test]
+- 583090b1b823 rebase
+- redhat/self-test: Initial commit (Ben Crocker)
+- generate_all_configs.sh: Fix syntax flagged by shellcheck (Ben Crocker)
+- process_configs.sh: Fix syntax flagged by shellcheck (Ben Crocker)
+
* Fri Oct 09 2020 Fedora Kernel Team <kernel-team@fedoraproject.org> [5.9.0-0.rc8.20201009git7575fdda569b.31]
- Modify patchlist changelog output (Don Zickus)
- Filter out LTO build options from the perl ccopts ("Justin M. Forbes")
diff --git a/patch-5.9.0-redhat.patch b/patch-5.9.0-redhat.patch
index 896d1e67d..092be636e 100644
--- a/patch-5.9.0-redhat.patch
+++ b/patch-5.9.0-redhat.patch
@@ -218,7 +218,7 @@ index 000000000000..effb81d04bfd
+
+endmenu
diff --git a/Makefile b/Makefile
-index f84d7e4ca0be..f10deca1183b 100644
+index 51540b291738..cb84fca3accc 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,10 @@ $(if $(filter __%, $(MAKECMDGOALS)), \
diff --git a/process_configs.sh b/process_configs.sh
index 92cc79701..c1e81ca16 100755
--- a/process_configs.sh
+++ b/process_configs.sh
@@ -3,6 +3,8 @@
# This script takes the merged config files and processes them through oldconfig
# and listnewconfig
#
+# Globally disable suggestion of appending '|| exit' or '|| return' to cd/pushd/popd commands
+# shellcheck disable=SC2164
usage()
{
@@ -35,11 +37,11 @@ switch_to_toplevel()
path="$(pwd)"
while test -n "$path"
do
- test -e $path/MAINTAINERS && \
- test -d $path/drivers && \
+ test -e "$path"/MAINTAINERS && \
+ test -d "$path"/drivers && \
break
- path="$(dirname $path)"
+ path=$(dirname "$path")
done
test -n "$path" || die "Can't find toplevel"
@@ -70,14 +72,14 @@ checkoptions()
print "Found "a[1]"="a[2]" after generation, had " a[1]"="configs[a[1]]" in Source tree";
}
}
- ' $1 $2 > .mismatches
+ ' "$1" "$2" > .mismatches
checkoptions_error=false
if test -s .mismatches
then
- while read LINE
+ while read -r LINE
do
- if find ./ -name $(echo $LINE | awk -F "=" ' { print $1 } ' | awk ' { print $2 }') | xargs grep ^ | grep -q "process_configs_known_broken"; then
+ if find ./ -name "$(echo "$LINE" | awk -F "=" ' { print $1 } ' | awk ' { print $2 }')" | xargs -0 grep ^ | grep -q "process_configs_known_broken"; then
# This is a known broken config.
# See script help warning.
checkoptions_error=false
@@ -104,7 +106,7 @@ parsenewconfigs()
# and puts it into CONFIG_FOO files. Using the output of
# listnewconfig is much easier to ensure we get the default
# output.
- /usr/bin/awk -v BASE=$tmpdir '
+ /usr/bin/awk -v BASE="$tmpdir" '
/is not set/ {
split ($0, a, "#");
split(a[2], b);
@@ -129,7 +131,7 @@ parsenewconfigs()
# each CONFIG_FOO file. Because of how awk works
# there's a lot of moving files around and catting to
# get what we need.
- /usr/bin/awk -v BASE=$tmpdir '
+ /usr/bin/awk -v BASE="$tmpdir" '
BEGIN { inpatch=0;
outfile="none";
symbol="none"; }
@@ -161,73 +163,71 @@ parsenewconfigs()
' .helpnewconfig
- pushd $tmpdir &> /dev/null
+ pushd "$tmpdir" &> /dev/null
rm fake_*
popd &> /dev/null
- for f in `ls $tmpdir`; do
- [[ -e "$tmpdir/$f" ]] || break
- cp $tmpdir/$f $SCRIPT_DIR/pending"$FLAVOR"/generic/
+ for f in "$tmpdir"/*; do
+ [[ -e "$f" ]] || break
+ cp "$f" "$SCRIPT_DIR/pending$FLAVOR/generic/"
done
- rm -rf $tmpdir
+ rm -rf "$tmpdir"
}
function commit_new_configs()
{
# assume we are in $source_tree/configs, need to get to top level
- pushd $(switch_to_toplevel) &>/dev/null
+ pushd "$(switch_to_toplevel)" &>/dev/null
- for cfg in $SCRIPT_DIR/${PACKAGE_NAME}${KVERREL}${SUBARCH}*.config
+ for cfg in "$SCRIPT_DIR/${PACKAGE_NAME}${KVERREL}${SUBARCH}"*.config
do
- arch=$(head -1 $cfg | cut -b 3-)
+ arch=$(head -1 "$cfg" | cut -b 3-)
cfgtmp="${cfg}.tmp"
cfgorig="${cfg}.orig"
- cat $cfg > $cfgorig
+ cat "$cfg" > "$cfgorig"
if [ "$arch" = "EMPTY" ]
then
# This arch is intentionally left blank
- rm -f "${cfg}.orig"
continue
fi
echo -n "Checking for new configs in $cfg ... "
- make ARCH=$arch KCONFIG_CONFIG=$cfgorig listnewconfig >& .listnewconfig
+ make ARCH="$arch" KCONFIG_CONFIG="$cfgorig" listnewconfig >& .listnewconfig
grep -E 'CONFIG_' .listnewconfig > .newoptions
if test -s .newoptions
then
- make ARCH=$arch KCONFIG_CONFIG=$cfgorig helpnewconfig >& .helpnewconfig
+ make ARCH="$arch" KCONFIG_CONFIG="$cfgorig" helpnewconfig >& .helpnewconfig
parsenewconfigs
fi
rm .newoptions
echo "done"
done
- git add $SCRIPT_DIR/pending"$FLAVOR"
+ git add "$SCRIPT_DIR/pending$FLAVOR"
git commit -m "[redhat] AUTOMATIC: New configs"
}
function process_configs()
{
# assume we are in $source_tree/configs, need to get to top level
- pushd $(switch_to_toplevel) &>/dev/null
+ pushd "$(switch_to_toplevel)" &>/dev/null
- for cfg in $SCRIPT_DIR/${PACKAGE_NAME}${KVERREL}${SUBARCH}*.config
+ for cfg in "$SCRIPT_DIR/${PACKAGE_NAME}${KVERREL}${SUBARCH}"*.config
do
- arch=$(head -1 $cfg | cut -b 3-)
+ arch=$(head -1 "$cfg" | cut -b 3-)
cfgtmp="${cfg}.tmp"
cfgorig="${cfg}.orig"
- cat $cfg > $cfgorig
+ cat "$cfg" > "$cfgorig"
if [ "$arch" = "EMPTY" ]
then
# This arch is intentionally left blank
- rm -f "${cfg}.orig"
continue
fi
echo -n "Processing $cfg ... "
- make ARCH=$arch KCONFIG_CONFIG=$cfgorig listnewconfig >& .listnewconfig
+ make ARCH="$arch" KCONFIG_CONFIG="$cfgorig" listnewconfig >& .listnewconfig
grep -E 'CONFIG_' .listnewconfig > .newoptions
if test -n "$NEWOPTIONS" && test -s .newoptions
then
@@ -252,21 +252,21 @@ function process_configs()
rm .listnewconfig
- make ARCH=$arch KCONFIG_CONFIG=$cfgorig olddefconfig > /dev/null || exit 1
- echo "# $arch" > ${cfgtmp}
- cat "${cfgorig}" >> ${cfgtmp}
+ make ARCH="$arch" KCONFIG_CONFIG="$cfgorig" olddefconfig > /dev/null || exit 1
+ echo "# $arch" > "$cfgtmp"
+ cat "$cfgorig" >> "$cfgtmp"
if test -n "$CHECKOPTIONS"
then
- checkoptions $cfg $cfgtmp
+ checkoptions "$cfg" "$cfgtmp"
fi
# if test run, don't overwrite original
if test -n "$TESTRUN"
then
- rm ${cfgtmp}
+ rm -f "$cfgtmp"
else
- mv ${cfgtmp} ${cfg}
+ mv "$cfgtmp" "$cfg"
fi
- rm -f ${cfgorig}
+ rm -f "$cfgorig"
echo "done"
done
rm "$SCRIPT_DIR"/*.config*.old
@@ -324,9 +324,8 @@ PACKAGE_NAME="${1:-kernel}" # defines the package name used
KVERREL="$(test -n "$2" && echo "-$2" || echo "")"
SUBARCH="$(test -n "$3" && echo "-$3" || echo "")"
FLAVOR="$(test -n "$4" && echo "-$4" || echo "-common")"
-SCRIPT="$(readlink -f $0)"
-OUTPUT_DIR="$PWD"
-SCRIPT_DIR="$(dirname $SCRIPT)"
+SCRIPT=$(readlink -f "$0")
+SCRIPT_DIR=$(dirname "$SCRIPT")
# Most RHEL options are options we want in Fedora so RHEL pending settings head
# to common/
@@ -336,7 +335,7 @@ then
fi
# to handle this script being a symlink
-cd $SCRIPT_DIR
+cd "$SCRIPT_DIR"
if test -n "$COMMITNEWCONFIGS"; then
commit_new_configs
diff --git a/sources b/sources
index 6efedbaa1..1551141e6 100644
--- a/sources
+++ b/sources
@@ -1,3 +1,3 @@
-SHA512 (linux-20201009git7575fdda569b.tar.xz) = 503ba552e3939aee5996d057f665fd8615e68bfccb5aea6051a5f929e70d2a7ff3b2e7f956e7862767673b376dcdf4fc16364bee58bcee2f494261d0fe97a4cf
-SHA512 (kernel-abi-whitelists-5.9.0-0.rc8.20201009git7575fdda569b.32.tar.bz2) = fa6f3e9e6c9d71668c5a09145d63cbd007ba901ae713d88c93708392defe404b60a7ffeb06ea2680435cdbe088a9b850b7249fb4f34e180ab657108f1b62b592
-SHA512 (kernel-kabi-dw-5.9.0-0.rc8.20201009git7575fdda569b.32.tar.bz2) = 6edccb372e454c77800e6364c7402e4276b3ee10af2b25d2960aa6d695909dc49aba9c9a0e035001515467cbc31e748da5c4a8d1c5ea9655dc5c6ff8106417dc
+SHA512 (linux-5.9.tar.xz) = cafd463ca0c9b256479b7dd774f908cedef6d265c44f99de075558ab923808ddfacda1377ae000ce02730c6611527bddffbfc4421bbc4f44fd8e59d97cbc4363
+SHA512 (kernel-abi-whitelists-5.9.0-36.tar.bz2) = 03a9111423353a35e3cbe4473e1317f5dcc9b0834b9413b49ebe878f0cc94a42d6b78688132790ae6ba081cc50d6725f1a49b313b8f899943d30d7d095c64f40
+SHA512 (kernel-kabi-dw-5.9.0-36.tar.bz2) = 3cd53709d27d6d75b4e45b44933d39fbf7eafb1933c750cbaf48dfb3424f7e4ffeadcf136800f388040549bbe8e4b5a47608381ec85247c1474f1958859594d9
href='#n1602'>1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639
/*
    SSSD

    Async LDAP Helper routines

    Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
    Copyright (C) 2010, rhafer@suse.de, Novell 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 <http://www.gnu.org/licenses/>.
*/

#include <sasl/sasl.h>
#include "util/util.h"
#include "util/sss_krb5.h"
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/ldap_common.h"

#define LDAP_X_SSSD_PASSWORD_EXPIRED 0x555D

errno_t deref_string_to_val(const char *str, int *val)
{
    if (strcasecmp(str, "never") == 0) {
        *val = LDAP_DEREF_NEVER;
    } else if (strcasecmp(str, "searching") == 0) {
        *val = LDAP_DEREF_SEARCHING;
    } else if (strcasecmp(str, "finding") == 0) {
        *val = LDAP_DEREF_FINDING;
    } else if (strcasecmp(str, "always") == 0) {
        *val = LDAP_DEREF_ALWAYS;
    } else {
        DEBUG(1, ("Illegal deref option [%s].\n", str));
        return EINVAL;
    }

    return EOK;
}

/* ==Connect-to-LDAP-Server=============================================== */

struct sdap_rebind_proc_params {
    struct sdap_options *opts;
    struct sdap_handle *sh;
    bool use_start_tls;
};

static int sdap_rebind_proc(LDAP *ldap, LDAP_CONST char *url, ber_tag_t request,
                            ber_int_t msgid, void *params);

struct sdap_connect_state {
    struct tevent_context *ev;
    struct sdap_options *opts;
    struct sdap_handle *sh;

    struct sdap_op *op;

    struct sdap_msg *reply;
    int result;
};

static void sdap_connect_done(struct sdap_op *op,
                              struct sdap_msg *reply,
                              int error, void *pvt);

struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx,
                                     struct tevent_context *ev,
                                     struct sdap_options *opts,
                                     const char *uri,
                                     bool use_start_tls)
{
    struct tevent_req *req;
    struct sdap_connect_state *state;
    struct timeval tv;
    int ver;
    int lret;
    int optret;
    int ret = EOK;
    int msgid;
    char *errmsg = NULL;
    bool ldap_referrals;
    const char *ldap_deref;
    int ldap_deref_val;
    struct sdap_rebind_proc_params *rebind_proc_params;

    req = tevent_req_create(memctx, &state, struct sdap_connect_state);
    if (!req) return NULL;

    state->reply = talloc(state, struct sdap_msg);
    if (!state->reply) {
        talloc_zfree(req);
        return NULL;
    }

    state->ev = ev;
    state->opts = opts;
    state->sh = sdap_handle_create(state);
    if (!state->sh) {
        talloc_zfree(req);
        return NULL;
    }
    /* Initialize LDAP handler */
    lret = ldap_initialize(&state->sh->ldap, uri);
    if (lret != LDAP_SUCCESS) {
        DEBUG(1, ("ldap_initialize failed: %s\n", ldap_err2string(lret)));
        goto fail;
    }

    /* Force ldap version to 3 */
    ver = LDAP_VERSION3;
    lret = ldap_set_option(state->sh->ldap, LDAP_OPT_PROTOCOL_VERSION, &ver);
    if (lret != LDAP_OPT_SUCCESS) {
        DEBUG(1, ("Failed to set ldap version to 3\n"));
        goto fail;
    }

    /* TODO: maybe this can be remove when we go async, currently we need it
     * to handle EINTR during poll(). */
    ret = ldap_set_option(state->sh->ldap, LDAP_OPT_RESTART, LDAP_OPT_ON);
    if (ret != LDAP_OPT_SUCCESS) {
        DEBUG(1, ("Failed to set restart option.\n"));
    }

    /* Set Network Timeout */
    tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT);
    tv.tv_usec = 0;
    lret = ldap_set_option(state->sh->ldap, LDAP_OPT_NETWORK_TIMEOUT, &tv);
    if (lret != LDAP_OPT_SUCCESS) {
        DEBUG(1, ("Failed to set network timeout to %d\n",
                  dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT)));
        goto fail;
    }

    /* Set Default Timeout */
    tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_OPT_TIMEOUT);
    tv.tv_usec = 0;
    lret = ldap_set_option(state->sh->ldap, LDAP_OPT_TIMEOUT, &tv);
    if (lret != LDAP_OPT_SUCCESS) {
        DEBUG(1, ("Failed to set default timeout to %d\n",
                  dp_opt_get_int(opts->basic, SDAP_OPT_TIMEOUT)));
        goto fail;
    }

    /* Set Referral chasing */
    ldap_referrals = dp_opt_get_bool(opts->basic, SDAP_REFERRALS);
    lret = ldap_set_option(state->sh->ldap, LDAP_OPT_REFERRALS,
                           (ldap_referrals ? LDAP_OPT_ON : LDAP_OPT_OFF));
    if (lret != LDAP_OPT_SUCCESS) {
        DEBUG(1, ("Failed to set referral chasing to %s\n",
                  (ldap_referrals ? "LDAP_OPT_ON" : "LDAP_OPT_OFF")));
        goto fail;
    }

    if (ldap_referrals) {
        rebind_proc_params = talloc_zero(state->sh,
                                         struct sdap_rebind_proc_params);
        if (rebind_proc_params == NULL) {
            DEBUG(1, ("talloc_zero failed.\n"));
            ret = ENOMEM;
            goto fail;
        }

        rebind_proc_params->opts = opts;
        rebind_proc_params->sh = state->sh;
        rebind_proc_params->use_start_tls = use_start_tls;

        lret = ldap_set_rebind_proc(state->sh->ldap, sdap_rebind_proc,
                                    rebind_proc_params);
        if (lret != LDAP_SUCCESS) {
            DEBUG(1, ("ldap_set_rebind_proc failed.\n"));
            goto fail;
        }
    }

    /* Set alias dereferencing */
    ldap_deref = dp_opt_get_string(opts->basic, SDAP_DEREF);
    if (ldap_deref != NULL) {
        ret = deref_string_to_val(ldap_deref, &ldap_deref_val);
        if (ret != EOK) {
            DEBUG(1, ("deref_string_to_val failed.\n"));
            goto fail;
        }

        lret = ldap_set_option(state->sh->ldap, LDAP_OPT_DEREF, &ldap_deref_val);
        if (lret != LDAP_OPT_SUCCESS) {
            DEBUG(1, ("Failed to set deref option to %d\n", ldap_deref_val));
            goto fail;
        }

    }

    ret = setup_ldap_connection_callbacks(state->sh, state->ev);
    if (ret != EOK) {
        DEBUG(1, ("setup_ldap_connection_callbacks failed.\n"));
        goto fail;
    }

    /* if we do not use start_tls the connection is not really connected yet
     * just fake an async procedure and leave connection to the bind call */
    if (!use_start_tls) {
        tevent_req_done(req);
        tevent_req_post(req, ev);
        return req;
    }

    DEBUG(4, ("Executing START TLS\n"));

    lret = ldap_start_tls(state->sh->ldap, NULL, NULL, &msgid);
    if (lret != LDAP_SUCCESS) {
        optret = ldap_get_option(state->sh->ldap,
                                 SDAP_DIAGNOSTIC_MESSAGE,
                                 (void*)&errmsg);
        if (optret == LDAP_SUCCESS) {
            DEBUG(3, ("ldap_start_tls failed: [%s] [%s]\n",
                      ldap_err2string(lret),
                      errmsg));
            sss_log(SSS_LOG_ERR, "Could not start TLS. %s", errmsg);
            ldap_memfree(errmsg);
        }
        else {
            DEBUG(3, ("ldap_start_tls failed: [%s]\n",
                      ldap_err2string(lret)));
            sss_log(SSS_LOG_ERR, "Could not start TLS. "
                                 "Check for certificate issues.");
        }
        goto fail;
    }

    ret = sdap_set_connected(state->sh, state->ev);
    if (ret) goto fail;

    /* FIXME: get timeouts from configuration, for now 5 secs. */
    ret = sdap_op_add(state, ev, state->sh, msgid,
                      sdap_connect_done, req, 5, &state->op);
    if (ret) {
        DEBUG(1, ("Failed to set up operation!\n"));
        goto fail;
    }

    return req;

fail:
    if (ret) {
        tevent_req_error(req, ret);
    } else {
        if (lret == LDAP_SERVER_DOWN) {
            tevent_req_error(req, ETIMEDOUT);
        } else {
            tevent_req_error(req, EIO);
        }
    }
    tevent_req_post(req, ev);
    return req;
}

static void sdap_connect_done(struct sdap_op *op,
                              struct sdap_msg *reply,
                              int error, void *pvt)
{
    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
    struct sdap_connect_state *state = tevent_req_data(req,
                                          struct sdap_connect_state);
    char *errmsg = NULL;
    char *tlserr;
    int ret;
    int optret;

    if (error) {
        tevent_req_error(req, error);
        return;
    }

    state->reply = talloc_steal(state, reply);

    ret = ldap_parse_result(state->sh->ldap, state->reply->msg,
                            &state->result, NULL, &errmsg, NULL, NULL, 0);
    if (ret != LDAP_SUCCESS) {
        DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid));
        tevent_req_error(req, EIO);
        return;
    }

    DEBUG(3, ("START TLS result: %s(%d), %s\n",
              ldap_err2string(state->result), state->result, errmsg));
    ldap_memfree(errmsg);

    if (ldap_tls_inplace(state->sh->ldap)) {
        DEBUG(9, ("SSL/TLS handler already in place.\n"));
        tevent_req_done(req);
        return;
    }

/* FIXME: take care that ldap_install_tls might block */
    ret = ldap_install_tls(state->sh->ldap);
    if (ret != LDAP_SUCCESS) {

        optret = ldap_get_option(state->sh->ldap,
                                 SDAP_DIAGNOSTIC_MESSAGE,
                                 (void*)&tlserr);
        if (optret == LDAP_SUCCESS) {
            DEBUG(3, ("ldap_install_tls failed: [%s] [%s]\n",
                      ldap_err2string(ret),
                      tlserr));
            sss_log(SSS_LOG_ERR, "Could not start TLS encryption. %s", tlserr);
            ldap_memfree(tlserr);
        }
        else {
            DEBUG(3, ("ldap_install_tls failed: [%s]\n",
                      ldap_err2string(ret)));
            sss_log(SSS_LOG_ERR, "Could not start TLS encryption. "
                                 "Check for certificate issues.");
        }

        state->result = ret;
        tevent_req_error(req, EIO);
        return;
    }

    tevent_req_done(req);
}

int sdap_connect_recv(struct tevent_req *req,
                      TALLOC_CTX *memctx,
                      struct sdap_handle **sh)
{
    struct sdap_connect_state *state = tevent_req_data(req,
                                                  struct sdap_connect_state);

    TEVENT_REQ_RETURN_ON_ERROR(req);

    *sh = talloc_steal(memctx, state->sh);
    if (!*sh) {
        return ENOMEM;
    }
    return EOK;
}

/* ==Simple-Bind========================================================== */

struct simple_bind_state {
    struct tevent_context *ev;
    struct sdap_handle *sh;
    const char *user_dn;
    struct berval *pw;

    struct sdap_op *op;

    struct sdap_msg *reply;
    struct sdap_ppolicy_data *ppolicy;
    int result;
};

static void simple_bind_done(struct sdap_op *op,
                             struct sdap_msg *reply,
                             int error, void *pvt);

static struct tevent_req *simple_bind_send(TALLOC_CTX *memctx,
                                           struct tevent_context *ev,
                                           struct sdap_handle *sh,
                                           const char *user_dn,
                                           struct berval *pw)
{
    struct tevent_req *req;
    struct simple_bind_state *state;
    int ret = EOK;
    int msgid;
    int ldap_err;
    LDAPControl **request_controls = NULL;
    LDAPControl *ctrls[2] = { NULL, NULL };

    req = tevent_req_create(memctx, &state, struct simple_bind_state);
    if (!req) return NULL;

    state->reply = talloc(state, struct sdap_msg);
    if (!state->reply) {
        talloc_zfree(req);
        return NULL;
    }

    state->ev = ev;
    state->sh = sh;
    state->user_dn = user_dn;
    state->pw = pw;

    ret = sdap_control_create(state->sh, LDAP_CONTROL_PASSWORDPOLICYREQUEST,
                              0, NULL, 0, &ctrls[0]);
    if (ret != LDAP_SUCCESS && ret != LDAP_NOT_SUPPORTED) {
        DEBUG(1, ("sdap_control_create failed to create "
                  "Password Policy control.\n"));
        goto fail;
    }
    request_controls = ctrls;

    DEBUG(4, ("Executing simple bind as: %s\n", state->user_dn));

    ret = ldap_sasl_bind(state->sh->ldap, state->user_dn, LDAP_SASL_SIMPLE,
                         state->pw, request_controls, NULL, &msgid);
    if (ctrls[0]) ldap_control_free(ctrls[0]);
    if (ret == -1 || msgid == -1) {
        ret = ldap_get_option(state->sh->ldap,
                              LDAP_OPT_RESULT_CODE, &ldap_err);
        if (ret != LDAP_OPT_SUCCESS) {
            DEBUG(1, ("ldap_bind failed (couldn't get ldap error)\n"));
            ret = LDAP_LOCAL_ERROR;
        } else {
            DEBUG(1, ("ldap_bind failed (%d)[%s]\n",
                      ldap_err, ldap_err2string(ldap_err)));
            ret = ldap_err;
        }
        goto fail;
    }
    DEBUG(8, ("ldap simple bind sent, msgid = %d\n", msgid));

    if (!sh->connected) {
        ret = sdap_set_connected(sh, ev);
        if (ret) goto fail;
    }

    /* FIXME: get timeouts from configuration, for now 5 secs. */
    ret = sdap_op_add(state, ev, sh, msgid,
                      simple_bind_done, req, 5, &state->op);
    if (ret) {
        DEBUG(1, ("Failed to set up operation!\n"));
        goto fail;
    }

    return req;

fail:
    if (ret == LDAP_SERVER_DOWN) {
        tevent_req_error(req, ETIMEDOUT);
    } else {
        tevent_req_error(req, EIO);
    }
    tevent_req_post(req, ev);
    return req;
}

static void simple_bind_done(struct sdap_op *op,
                             struct sdap_msg *reply,
                             int error, void *pvt)
{
    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
    struct simple_bind_state *state = tevent_req_data(req,
                                            struct simple_bind_state);
    char *errmsg = NULL;
    int ret;
    LDAPControl **response_controls;
    int c;
    ber_int_t pp_grace;
    ber_int_t pp_expire;
    LDAPPasswordPolicyError pp_error;

    if (error) {
        tevent_req_error(req, error);
        return;
    }

    state->reply = talloc_steal(state, reply);

    ret = ldap_parse_result(state->sh->ldap, state->reply->msg,
                            &state->result, NULL, &errmsg, NULL,
                            &response_controls, 0);
    if (ret != LDAP_SUCCESS) {
        DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid));
        ret = EIO;
        goto done;
    }

    if (response_controls == NULL) {
        DEBUG(5, ("Server returned no controls.\n"));
        state->ppolicy = NULL;
    } else {
        for (c = 0; response_controls[c] != NULL; c++) {
            DEBUG(9, ("Server returned control [%s].\n",
                      response_controls[c]->ldctl_oid));
            if (strcmp(response_controls[c]->ldctl_oid,
                       LDAP_CONTROL_PASSWORDPOLICYRESPONSE) == 0) {
                ret = ldap_parse_passwordpolicy_control(state->sh->ldap,
                                                        response_controls[c],
                                                        &pp_expire, &pp_grace,
                                                        &pp_error);
                if (ret != LDAP_SUCCESS) {
                    DEBUG(1, ("ldap_parse_passwordpolicy_control failed.\n"));
                    ret = EIO;
                    goto done;
                }

                DEBUG(7, ("Password Policy Response: expire [%d] grace [%d] "
                          "error [%s].\n", pp_expire, pp_grace,
                          ldap_passwordpolicy_err2txt(pp_error)));
                state->ppolicy = talloc(state, struct sdap_ppolicy_data);
                if (state->ppolicy == NULL) {
                    DEBUG(1, ("talloc failed.\n"));
                    ret = ENOMEM;
                    goto done;
                }
                state->ppolicy->grace = pp_grace;
                state->ppolicy->expire = pp_expire;
                if (state->result == LDAP_SUCCESS) {
                    if (pp_error == PP_changeAfterReset) {
                        DEBUG(4, ("Password was reset. "
                                  "User must set a new password.\n"));
                        state->result = LDAP_X_SSSD_PASSWORD_EXPIRED;
                    } else if (pp_grace > 0) {
                        DEBUG(4, ("Password expired. "
                                  "[%d] grace logins remaining.\n", pp_grace));
                    } else if (pp_expire > 0) {
                        DEBUG(4, ("Password will expire in [%d] seconds.\n",
                                  pp_expire));
                    }
                } else if (state->result == LDAP_INVALID_CREDENTIALS &&
                           pp_error == PP_passwordExpired) {
                    DEBUG(4,
                          ("Password expired user must set a new password.\n"));
                    state->result = LDAP_X_SSSD_PASSWORD_EXPIRED;
                }
            }
        }
    }

    DEBUG(3, ("Bind result: %s(%d), %s\n",
              ldap_err2string(state->result), state->result, errmsg));

    ret = LDAP_SUCCESS;
done:
    ldap_controls_free(response_controls);
    ldap_memfree(errmsg);

    if (ret == LDAP_SUCCESS) {
        tevent_req_done(req);
    } else {
        tevent_req_error(req, ret);
    }
}

static int simple_bind_recv(struct tevent_req *req,
                            TALLOC_CTX *memctx,
                            int *ldaperr,
                            struct sdap_ppolicy_data **ppolicy)
{
    struct simple_bind_state *state = tevent_req_data(req,
                                            struct simple_bind_state);

    *ldaperr = LDAP_OTHER;
    TEVENT_REQ_RETURN_ON_ERROR(req);

    *ldaperr = state->result;
    *ppolicy = talloc_steal(memctx, state->ppolicy);
    return EOK;
}

/* ==SASL-Bind============================================================ */

struct sasl_bind_state {
    struct tevent_context *ev;
    struct sdap_handle *sh;

    const char *sasl_mech;
    const char *sasl_user;
    struct berval *sasl_cred;

    int result;
};

static int sdap_sasl_interact(LDAP *ld, unsigned flags,
                              void *defaults, void *interact);

static struct tevent_req *sasl_bind_send(TALLOC_CTX *memctx,
                                         struct tevent_context *ev,
                                         struct sdap_handle *sh,
                                         const char *sasl_mech,
                                         const char *sasl_user,
                                         struct berval *sasl_cred)
{
    struct tevent_req *req;
    struct sasl_bind_state *state;
    int ret = EOK;

    req = tevent_req_create(memctx, &state, struct sasl_bind_state);
    if (!req) return NULL;

    state->ev = ev;
    state->sh = sh;
    state->sasl_mech = sasl_mech;
    state->sasl_user = sasl_user;
    state->sasl_cred = sasl_cred;

    DEBUG(4, ("Executing sasl bind mech: %s, user: %s\n",
              sasl_mech, sasl_user));

    /* FIXME: Warning, this is a sync call!
     * No async variant exist in openldap libraries yet */

    ret = ldap_sasl_interactive_bind_s(state->sh->ldap, NULL,
                                       sasl_mech, NULL, NULL,
                                       LDAP_SASL_QUIET,
                                       (*sdap_sasl_interact), state);
    state->result = ret;
    if (ret != LDAP_SUCCESS) {
        DEBUG(1, ("ldap_sasl_bind failed (%d)[%s]\n",
                  ret, ldap_err2string(ret)));
        goto fail;
    }

    if (!sh->connected) {
        ret = sdap_set_connected(sh, ev);
        if (ret) goto fail;
    }

    tevent_req_post(req, ev);
    return req;

fail:
    if (ret == LDAP_SERVER_DOWN) {
        tevent_req_error(req, ETIMEDOUT);
    } else {
        tevent_req_error(req, EIO);
    }
    tevent_req_post(req, ev);
    return req;
}

static int sdap_sasl_interact(LDAP *ld, unsigned flags,
                              void *defaults, void *interact)
{
    struct sasl_bind_state *state = talloc_get_type(defaults,
                                                    struct sasl_bind_state);
    sasl_interact_t *in = (sasl_interact_t *)interact;

    if (!ld) return LDAP_PARAM_ERROR;

    while (in->id != SASL_CB_LIST_END) {

        switch (in->id) {
        case SASL_CB_GETREALM:
        case SASL_CB_USER:
        case SASL_CB_PASS:
            if (in->defresult) {
                in->result = in->defresult;
            } else {
                in->result = "";
            }
            in->len = strlen(in->result);
            break;
        case SASL_CB_AUTHNAME:
            if (state->sasl_user) {
                in->result = state->sasl_user;
            } else if (in->defresult) {
                in->result = in->defresult;
            } else {
                in->result = "";
            }
            in->len = strlen(in->result);
            break;
        case SASL_CB_NOECHOPROMPT:
        case SASL_CB_ECHOPROMPT:
            goto fail;
        }

        in++;
    }

    return LDAP_SUCCESS;

fail:
    return LDAP_UNAVAILABLE;
}

static int sasl_bind_recv(struct tevent_req *req, int *ldaperr)
{
    struct sasl_bind_state *state = tevent_req_data(req,
                                            struct sasl_bind_state);
    enum tevent_req_state tstate;
    uint64_t err = EIO;

    if (tevent_req_is_error(req, &tstate, &err)) {
        if (tstate != TEVENT_REQ_IN_PROGRESS) {
            *ldaperr = LDAP_OTHER;
            return err;
        }
    }

    *ldaperr = state->result;
    return EOK;
}

/* ==Perform-Kinit-given-keytab-and-principal============================= */

struct sdap_kinit_state {
    const char *keytab;
    const char *principal;
    const char *realm;
    int    timeout;
    int    lifetime;

    const char *krb_service_name;
    struct tevent_context *ev;
    struct be_ctx *be;

    struct fo_server *kdc_srv;
    int result;
    time_t expire_time;
};

static void sdap_kinit_done(struct tevent_req *subreq);
static struct tevent_req *sdap_kinit_next_kdc(struct tevent_req *req);
static void sdap_kinit_kdc_resolved(struct tevent_req *subreq);

struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx,
                                   struct tevent_context *ev,
                                   struct be_ctx *be,
                                   struct sdap_handle *sh,
                                   const char *krb_service_name,
                                   int    timeout,
                                   const char *keytab,
                                   const char *principal,
                                   const char *realm,
                                   int lifetime)
{
    struct tevent_req *req;
    struct tevent_req *subreq;
    struct sdap_kinit_state *state;
    int ret;

    DEBUG(6, ("Attempting kinit (%s, %s, %s, %d)\n", keytab, principal, realm,
                                                     lifetime));

    if (lifetime < 0 || lifetime > INT32_MAX) {
        DEBUG(1, ("Ticket lifetime out of range.\n"));
        return NULL;
    }

    req = tevent_req_create(memctx, &state, struct sdap_kinit_state);
    if (!req) return NULL;

    state->result = SDAP_AUTH_FAILED;
    state->keytab = keytab;
    state->principal = principal;
    state->realm = realm;
    state->ev = ev;
    state->be = be;
    state->timeout = timeout;
    state->lifetime = lifetime;
    state->krb_service_name = krb_service_name;

    if (keytab) {
        ret = setenv("KRB5_KTNAME", keytab, 1);
        if (ret == -1) {
            DEBUG(2, ("Failed to set KRB5_KTNAME to %s\n", keytab));
            talloc_free(req);
            return NULL;
        }
    }

    subreq = sdap_kinit_next_kdc(req);
    if (!subreq) {
        talloc_free(req);
        return NULL;
    }

    return req;
}

static struct tevent_req *sdap_kinit_next_kdc(struct tevent_req *req)
{
    struct tevent_req *next_req;
    struct sdap_kinit_state *state = tevent_req_data(req,
                                                    struct sdap_kinit_state);

    DEBUG(7, ("Resolving next KDC for service %s\n", state->krb_service_name));

    next_req = be_resolve_server_send(state, state->ev,
                                      state->be,
                                      state->krb_service_name);
    if (next_req == NULL) {
        DEBUG(1, ("be_resolve_server_send failed.\n"));
        return NULL;
    }
    tevent_req_set_callback(next_req, sdap_kinit_kdc_resolved, req);

    return next_req;
}

static void sdap_kinit_kdc_resolved(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    struct sdap_kinit_state *state = tevent_req_data(req,
                                                     struct sdap_kinit_state);
    struct tevent_req *tgtreq;
    int ret;

    ret = be_resolve_server_recv(subreq, &state->kdc_srv);
    talloc_zfree(subreq);
    if (ret != EOK) {
        /* all servers have been tried and none
         * was found good, go offline */
        tevent_req_error(req, EIO);
        return;
    }

    DEBUG(7, ("KDC resolved, attempting to get TGT...\n"));

    tgtreq = sdap_get_tgt_send(state, state->ev, state->realm,
                               state->principal, state->keytab,
                               state->lifetime, state->timeout);
    if (!tgtreq) {
        tevent_req_error(req, ENOMEM);
        return;
    }
    tevent_req_set_callback(tgtreq, sdap_kinit_done, req);
}

static void sdap_kinit_done(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    struct sdap_kinit_state *state = tevent_req_data(req,
                                                     struct sdap_kinit_state);

    int ret;
    int result;
    char *ccname = NULL;
    time_t expire_time;
    krb5_error_code kerr;
    struct tevent_req *nextreq;

    ret = sdap_get_tgt_recv(subreq, state, &result,
                            &kerr, &ccname, &expire_time);
    talloc_zfree(subreq);
    if (ret != EOK) {
        state->result = SDAP_AUTH_FAILED;
        DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret)));
        tevent_req_error(req, ret);
        return;
    }

    if (result == EOK) {
        ret = setenv("KRB5CCNAME", ccname, 1);
        if (ret == -1) {
            DEBUG(2, ("Unable to set env. variable KRB5CCNAME!\n"));
            state->result = SDAP_AUTH_FAILED;
            tevent_req_error(req, EFAULT);
        }

        state->expire_time = expire_time;
        state->result = SDAP_AUTH_SUCCESS;
        tevent_req_done(req);
        return;
    } else {
        if (kerr == KRB5_KDC_UNREACH) {
            fo_set_port_status(state->kdc_srv, PORT_NOT_WORKING);
            nextreq = sdap_kinit_next_kdc(req);
            if (!nextreq) {
                tevent_req_error(req, ENOMEM);
            }
            return;
        }

    }

    DEBUG(4, ("Could not get TGT: %d [%s]\n", result, strerror(result)));
    state->result = SDAP_AUTH_FAILED;
    tevent_req_error(req, EIO);
}

int sdap_kinit_recv(struct tevent_req *req,
                    enum sdap_result *result,
                    time_t *expire_time)
{
    struct sdap_kinit_state *state = tevent_req_data(req,
                                                     struct sdap_kinit_state);
    enum tevent_req_state tstate;
    uint64_t err = EIO;

    if (tevent_req_is_error(req, &tstate, &err)) {
        if (tstate != TEVENT_REQ_IN_PROGRESS) {
            *result = SDAP_ERROR;
            return err;
        }
    }

    *result = state->result;
    *expire_time = state->expire_time;
    return EOK;
}


/* ==Authenticaticate-User-by-DN========================================== */

struct sdap_auth_state {
    const char *user_dn;
    struct berval pw;
    struct sdap_ppolicy_data *ppolicy;

    int result;
    bool is_sasl;
};

static void sdap_auth_done(struct tevent_req *subreq);
static int sdap_auth_get_authtok(TALLOC_CTX *memctx,
                                 const char *authtok_type,
                                 struct dp_opt_blob authtok,
                                 struct berval *pw);

/* TODO: handle sasl_cred */
struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
                                  struct tevent_context *ev,
                                  struct sdap_handle *sh,
                                  const char *sasl_mech,
                                  const char *sasl_user,
                                  const char *user_dn,
                                  const char *authtok_type,
                                  struct dp_opt_blob authtok)
{
    struct tevent_req *req, *subreq;
    struct sdap_auth_state *state;
    int ret;

    req = tevent_req_create(memctx, &state, struct sdap_auth_state);
    if (!req) return NULL;

    state->user_dn = user_dn;

    ret = sdap_auth_get_authtok(state, authtok_type, authtok, &state->pw);
    if (ret != EOK) {
        if (ret == ENOSYS) {
            DEBUG(1, ("Getting authtok is not supported with the "
                      "crypto library compiled with, authentication "
                      "might fail!\n"));
        } else {
            DEBUG(1, ("Cannot parse authtok.\n"));
            tevent_req_error(req, ret);
            return tevent_req_post(req, ev);
        }
    }

    if (sasl_mech) {
        state->is_sasl = true;
        subreq = sasl_bind_send(state, ev, sh, sasl_mech, sasl_user, NULL);
        if (!subreq) {
            tevent_req_error(req, ENOMEM);
            return tevent_req_post(req, ev);
        }
    } else {
        state->is_sasl = false;
        subreq = simple_bind_send(state, ev, sh, user_dn, &state->pw);
        if (!subreq) {
            tevent_req_error(req, ENOMEM);
            return tevent_req_post(req, ev);
        }
    }

    tevent_req_set_callback(subreq, sdap_auth_done, req);
    return req;
}

static int sdap_auth_get_authtok(TALLOC_CTX *mem_ctx,
                                 const char *authtok_type,
                                 struct dp_opt_blob authtok,
                                 struct berval *pw)
{
    if (!authtok_type) return EOK;
    if (!pw) return EINVAL;

    if (strcasecmp(authtok_type,"password") == 0) {
        pw->bv_len = authtok.length;
        pw->bv_val = (char *) authtok.data;
    } else {
        DEBUG(1, ("Authentication token type [%s] is not supported\n",
                  authtok_type));
        return EINVAL;
    }

    return EOK;
}

static void sdap_auth_done(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    struct sdap_auth_state *state = tevent_req_data(req,
                                                 struct sdap_auth_state);
    int ret;

    if (state->is_sasl) {
        ret = sasl_bind_recv(subreq, &state->result);
        state->ppolicy = NULL;
    } else {
        ret = simple_bind_recv(subreq, state, &state->result, &state->ppolicy);
    }
    if (ret != EOK) {
        tevent_req_error(req, ret);
        return;
    }

    tevent_req_done(req);
}

int sdap_auth_recv(struct tevent_req *req,
                   TALLOC_CTX *memctx,
                   enum sdap_result *result,
                   struct sdap_ppolicy_data **ppolicy)
{
    struct sdap_auth_state *state = tevent_req_data(req,
                                                 struct sdap_auth_state);

    *result = SDAP_ERROR;
    TEVENT_REQ_RETURN_ON_ERROR(req);

    if (ppolicy != NULL) {
        *ppolicy = talloc_steal(memctx, state->ppolicy);
    }
    switch (state->result) {
        case LDAP_SUCCESS:
            *result = SDAP_AUTH_SUCCESS;
            break;
        case LDAP_INVALID_CREDENTIALS:
            *result = SDAP_AUTH_FAILED;
            break;
        case LDAP_X_SSSD_PASSWORD_EXPIRED:
            *result = SDAP_AUTH_PW_EXPIRED;
            break;
        default:
            break;
    }

    return EOK;
}

/* ==Client connect============================================ */

struct sdap_cli_connect_state {
    struct tevent_context *ev;
    struct sdap_options *opts;
    struct sdap_service *service;
    struct be_ctx *be;

    bool use_rootdse;

    struct sdap_handle *sh;

    struct fo_server *srv;

    struct sdap_server_opts *srv_opts;
};

static int sdap_cli_resolve_next(struct tevent_req *req);
static void sdap_cli_resolve_done(struct tevent_req *subreq);
static void sdap_cli_connect_done(struct tevent_req *subreq);
static void sdap_cli_rootdse_step(struct tevent_req *req);
static void sdap_cli_rootdse_done(struct tevent_req *subreq);
static void sdap_cli_kinit_step(struct tevent_req *req);
static void sdap_cli_kinit_done(struct tevent_req *subreq);
static void sdap_cli_auth_step(struct tevent_req *req);
static void sdap_cli_auth_done(struct tevent_req *subreq);

struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
                                         struct tevent_context *ev,
                                         struct sdap_options *opts,
                                         struct be_ctx *be,
                                         struct sdap_service *service,
                                         bool skip_rootdse)
{
    struct sdap_cli_connect_state *state;
    struct tevent_req *req;
    int ret;

    req = tevent_req_create(memctx, &state, struct sdap_cli_connect_state);
    if (!req) return NULL;

    state->ev = ev;
    state->opts = opts;
    state->service = service;
    state->be = be;
    state->srv = NULL;
    state->srv_opts = NULL;
    state->be = be;
    state->use_rootdse = !skip_rootdse;

    ret = sdap_cli_resolve_next(req);
    if (ret) {
        tevent_req_error(req, ret);
        tevent_req_post(req, ev);
    }
    return req;
}

static int sdap_cli_resolve_next(struct tevent_req *req)
{
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    struct tevent_req *subreq;

    /* Before stepping to next server  destroy any connection from previous attempt */
    talloc_zfree(state->sh);

    /* NOTE: this call may cause service->uri to be refreshed
     * with a new valid server. Do not use service->uri before */
    subreq = be_resolve_server_send(state, state->ev,
                                    state->be, state->service->name);
    if (!subreq) {
        return ENOMEM;
    }

    tevent_req_set_callback(subreq, sdap_cli_resolve_done, req);
    return EOK;
}

static void sdap_cli_resolve_done(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    int ret;
    bool use_tls = dp_opt_get_bool(state->opts->basic,
                                   SDAP_ID_TLS);

    ret = be_resolve_server_recv(subreq, &state->srv);
    talloc_zfree(subreq);
    if (ret) {
        state->srv = NULL;
        /* all servers have been tried and none
         * was found good, go offline */
        tevent_req_error(req, EIO);
        return;
    }

    if (use_tls && sdap_is_secure_uri(state->service->uri)) {
        DEBUG(8, ("[%s] is a secure channel. No need to run START_TLS\n",
                  state->service->uri));
        use_tls = false;
    }

    subreq = sdap_connect_send(state, state->ev, state->opts,
                               state->service->uri,
                               use_tls);
    if (!subreq) {
        tevent_req_error(req, ENOMEM);
        return;
    }
    tevent_req_set_callback(subreq, sdap_cli_connect_done, req);
}

static void sdap_cli_connect_done(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    const char *sasl_mech;
    int ret;

    talloc_zfree(state->sh);
    ret = sdap_connect_recv(subreq, state, &state->sh);
    talloc_zfree(subreq);
    if (ret) {
        if (ret == ETIMEDOUT) { /* retry another server */
            fo_set_port_status(state->srv, PORT_NOT_WORKING);
            ret = sdap_cli_resolve_next(req);
            if (ret != EOK) {
                tevent_req_error(req, ret);
            }
            return;
        }

        tevent_req_error(req, ret);
        return;
    }

    if (state->use_rootdse) {
        /* fetch the rootDSE this time */
        sdap_cli_rootdse_step(req);
        return;
    }

    sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);

    if (sasl_mech && state->use_rootdse) {
        /* check if server claims to support GSSAPI */
        if (!sdap_is_sasl_mech_supported(state->sh, sasl_mech)) {
            tevent_req_error(req, ENOTSUP);
            return;
        }
    }

    if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) {
        if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) {
            sdap_cli_kinit_step(req);
            return;
        }
    }

    sdap_cli_auth_step(req);
}

static void sdap_cli_rootdse_step(struct tevent_req *req)
{
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    struct tevent_req *subreq;
    int ret;

    subreq = sdap_get_rootdse_send(state, state->ev, state->opts, state->sh);
    if (!subreq) {
        tevent_req_error(req, ENOMEM);
        return;
    }
    tevent_req_set_callback(subreq, sdap_cli_rootdse_done, req);

    if (!state->sh->connected) {
    /* this rootdse search is performed before we actually do a bind,
     * so we need to set up the callbacks or we will never get notified
     * of a reply */

        ret = sdap_set_connected(state->sh, state->ev);
        if (ret) {
            tevent_req_error(req, ret);
        }
    }
}

static void sdap_cli_rootdse_done(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    struct sysdb_attrs *rootdse;
    const char *sasl_mech;
    int ret;

    ret = sdap_get_rootdse_recv(subreq, state, &rootdse);
    talloc_zfree(subreq);
    if (ret) {
        if (ret == ETIMEDOUT) { /* retry another server */
            fo_set_port_status(state->srv, PORT_NOT_WORKING);
            ret = sdap_cli_resolve_next(req);
            if (ret != EOK) {
                tevent_req_error(req, ret);
            }
            return;
        }

        else if (ret == ENOENT) {
            /* RootDSE was not available on
             * the server.
             * Continue, and just assume that the
             * features requested by the config
             * work properly.
             */
            state->use_rootdse = false;
        }

        else {
            tevent_req_error(req, ret);
            return;
        }
    }

    if (state->use_rootdse) {
        /* save rootdse data about supported features */
        ret = sdap_set_rootdse_supported_lists(rootdse, state->sh);
        if (ret) {
            tevent_req_error(req, ret);
            return;
        }

        ret = sdap_set_config_options_with_rootdse(rootdse, state->sh,
                                                   state->opts);
        if (ret) {
            DEBUG(1, ("sdap_set_config_options_with_rootdse failed.\n"));
            tevent_req_error(req, ret);
            return;
        }

    }

    ret = sdap_get_server_opts_from_rootdse(state,
                                            state->service->uri, rootdse,
                                            state->opts, &state->srv_opts);
    if (ret) {
        DEBUG(1, ("sdap_get_server_opts_from_rootdse failed.\n"));
        tevent_req_error(req, ret);
        return;
    }

    sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);

    if (sasl_mech && state->use_rootdse) {
        /* check if server claims to support GSSAPI */
        if (!sdap_is_sasl_mech_supported(state->sh, sasl_mech)) {
            tevent_req_error(req, ENOTSUP);
            return;
        }
    }

    if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) {
        if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) {
            sdap_cli_kinit_step(req);
            return;
        }
    }

    sdap_cli_auth_step(req);
}

static void sdap_cli_kinit_step(struct tevent_req *req)
{
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    struct tevent_req *subreq;

    subreq = sdap_kinit_send(state, state->ev,
                             state->be,
                             state->sh,
                             state->service->kinit_service_name,
                        dp_opt_get_int(state->opts->basic,
                                                   SDAP_OPT_TIMEOUT),
                        dp_opt_get_string(state->opts->basic,
                                                   SDAP_KRB5_KEYTAB),
                        dp_opt_get_string(state->opts->basic,
                                                   SDAP_SASL_AUTHID),
                        dp_opt_get_string(state->opts->basic,
                                                   SDAP_KRB5_REALM),
                        dp_opt_get_int(state->opts->basic,
                                                   SDAP_KRB5_TICKET_LIFETIME));
    if (!subreq) {
        tevent_req_error(req, ENOMEM);
        return;
    }
    tevent_req_set_callback(subreq, sdap_cli_kinit_done, req);
}

static void sdap_cli_kinit_done(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    enum sdap_result result;
    time_t expire_time;
    int ret;

    ret = sdap_kinit_recv(subreq, &result, &expire_time);
    talloc_zfree(subreq);
    if (ret) {
        if (ret == ETIMEDOUT) { /* child timed out, retry another server */
            fo_set_port_status(state->srv, PORT_NOT_WORKING);
            ret = sdap_cli_resolve_next(req);
            if (ret != EOK) {
                tevent_req_error(req, ret);
            }
            return;
        }

        tevent_req_error(req, ret);
        return;
    }
    if (result != SDAP_AUTH_SUCCESS) {
        tevent_req_error(req, EACCES);
        return;
    }
    state->sh->expire_time = expire_time;

    sdap_cli_auth_step(req);
}

static void sdap_cli_auth_step(struct tevent_req *req)
{
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    struct tevent_req *subreq;

    subreq = sdap_auth_send(state,
                            state->ev,
                            state->sh,
                            dp_opt_get_string(state->opts->basic,
                                                          SDAP_SASL_MECH),
                            dp_opt_get_string(state->opts->basic,
                                                        SDAP_SASL_AUTHID),
                            dp_opt_get_string(state->opts->basic,
                                                    SDAP_DEFAULT_BIND_DN),
                            dp_opt_get_string(state->opts->basic,
                                               SDAP_DEFAULT_AUTHTOK_TYPE),
                            dp_opt_get_blob(state->opts->basic,
                                                    SDAP_DEFAULT_AUTHTOK));
    if (!subreq) {
        tevent_req_error(req, ENOMEM);
        return;
    }
    tevent_req_set_callback(subreq, sdap_cli_auth_done, req);
}

static void sdap_cli_auth_done(struct tevent_req *subreq)
{
    struct tevent_req *req = tevent_req_callback_data(subreq,
                                                      struct tevent_req);
    enum sdap_result result;
    int ret;

    ret = sdap_auth_recv(subreq, NULL, &result, NULL);
    talloc_zfree(subreq);
    if (ret) {
        tevent_req_error(req, ret);
        return;
    }
    if (result != SDAP_AUTH_SUCCESS) {
        tevent_req_error(req, EACCES);
        return;
    }

    tevent_req_done(req);
}

int sdap_cli_connect_recv(struct tevent_req *req,
                          TALLOC_CTX *memctx,
                          bool *can_retry,
                          struct sdap_handle **gsh,
                          struct sdap_server_opts **srv_opts)
{
    struct sdap_cli_connect_state *state = tevent_req_data(req,
                                             struct sdap_cli_connect_state);
    enum tevent_req_state tstate;
    uint64_t err;

    if (can_retry) {
        *can_retry = true;
    }
    if (tevent_req_is_error(req, &tstate, &err)) {
        /* mark the server as bad if connection failed */
        if (state->srv) {
            fo_set_port_status(state->srv, PORT_NOT_WORKING);
        } else {
            if (can_retry) {
                *can_retry = false;
            }
        }

        if (tstate == TEVENT_REQ_USER_ERROR) {
            return err;
        }
        return EIO;
    } else if (state->srv) {
        fo_set_port_status(state->srv, PORT_WORKING);
    }

    if (gsh) {
        if (*gsh) {
            talloc_zfree(*gsh);
        }
        *gsh = talloc_steal(memctx, state->sh);
        if (!*gsh) {
            return ENOMEM;
        }
    } else {
        talloc_zfree(state->sh);
    }

    if (srv_opts) {
        *srv_opts = talloc_steal(memctx, state->srv_opts);
    }

    return EOK;
}

static int synchronous_tls_setup(LDAP *ldap)
{
    int lret;
    int optret;
    int ldaperr;
    int msgid;
    char *errmsg = NULL;
    LDAPMessage *result;

    DEBUG(4, ("Executing START TLS\n"));

    lret = ldap_start_tls(ldap, NULL, NULL, &msgid);
    if (lret != LDAP_SUCCESS) {
        optret = ldap_get_option(ldap, SDAP_DIAGNOSTIC_MESSAGE, (void*)&errmsg);
        if (optret == LDAP_SUCCESS) {
            DEBUG(3, ("ldap_start_tls failed: [%s] [%s]\n",
                      ldap_err2string(lret), errmsg));
            sss_log(SSS_LOG_ERR, "Could not start TLS. %s", errmsg);
            ldap_memfree(errmsg);
        } else {
            DEBUG(3, ("ldap_start_tls failed: [%s]\n", ldap_err2string(lret)));
            sss_log(SSS_LOG_ERR, "Could not start TLS. "
                                 "Check for certificate issues.");
        }
        return lret;
    }

    lret = ldap_result(ldap, msgid, 1, NULL, &result);
    if (lret != LDAP_RES_EXTENDED) {
        DEBUG(2, ("Unexpected ldap_result, expected [%d] got [%d].\n",
                  LDAP_RES_EXTENDED, lret));
        return LDAP_PARAM_ERROR;
    }

    lret = ldap_parse_result(ldap, result, &ldaperr, NULL, &errmsg, NULL, NULL,
                             0);
    if (lret != LDAP_SUCCESS) {
        DEBUG(2, ("ldap_parse_result failed (%d) [%d][%s]\n", msgid, lret,
                  ldap_err2string(lret)));
        return lret;
    }

    DEBUG(3, ("START TLS result: %s(%d), %s\n",
              ldap_err2string(ldaperr), ldaperr, errmsg));
    ldap_memfree(errmsg);

    if (ldap_tls_inplace(ldap)) {
        DEBUG(9, ("SSL/TLS handler already in place.\n"));
        return LDAP_SUCCESS;
    }

    lret = ldap_install_tls(ldap);
    if (lret != LDAP_SUCCESS) {

        optret = ldap_get_option(ldap, SDAP_DIAGNOSTIC_MESSAGE, (void*)&errmsg);
        if (optret == LDAP_SUCCESS) {
            DEBUG(3, ("ldap_install_tls failed: [%s] [%s]\n",
                      ldap_err2string(lret), errmsg));
            sss_log(SSS_LOG_ERR, "Could not start TLS encryption. %s", errmsg);
            ldap_memfree(errmsg);
        } else {
            DEBUG(3, ("ldap_install_tls failed: [%s]\n",
                      ldap_err2string(lret)));
            sss_log(SSS_LOG_ERR, "Could not start TLS encryption. "
                                 "Check for certificate issues.");
        }

        return lret;
    }

    return LDAP_SUCCESS;
}

static int sdap_rebind_proc(LDAP *ldap, LDAP_CONST char *url, ber_tag_t request,
                            ber_int_t msgid, void *params)
{
    struct sdap_rebind_proc_params *p = talloc_get_type(params,
                                                struct sdap_rebind_proc_params);
    const char *sasl_mech;
    const char *user_dn;
    struct berval password = {0, NULL};
    LDAPControl **request_controls = NULL;
    LDAPControl *ctrls[2] = { NULL, NULL };
    TALLOC_CTX *tmp_ctx = NULL;
    struct sasl_bind_state *sasl_bind_state;
    int ret;

    if (p->use_start_tls) {
        ret = synchronous_tls_setup(ldap);
        if (ret != EOK) {
            DEBUG(1, ("synchronous_tls_setup failed.\n"));
            return ret;
        }
    }

    tmp_ctx = talloc_new(NULL);
    if (tmp_ctx == NULL) {
        DEBUG(1, ("talloc_new failed.\n"));
        return LDAP_NO_MEMORY;
    }

    sasl_mech = dp_opt_get_string(p->opts->basic, SDAP_SASL_MECH);

    if (sasl_mech == NULL) {
        ret = sdap_control_create(p->sh, LDAP_CONTROL_PASSWORDPOLICYREQUEST,
                                  0, NULL, 0, &ctrls[0]);
        if (ret != LDAP_SUCCESS && ret != LDAP_NOT_SUPPORTED) {
            DEBUG(1, ("sdap_control_create failed to create "
                      "Password Policy control.\n"));
            goto done;
        }
        request_controls = ctrls;

        user_dn = dp_opt_get_string(p->opts->basic, SDAP_DEFAULT_BIND_DN);
        if (user_dn != NULL) {
            ret = sdap_auth_get_authtok(tmp_ctx,
                                        dp_opt_get_string(p->opts->basic,
                                                     SDAP_DEFAULT_AUTHTOK_TYPE),
                                        dp_opt_get_blob(p->opts->basic,
                                                        SDAP_DEFAULT_AUTHTOK),
                                        &password);
            if (ret != EOK) {
                DEBUG(1, ("sdap_auth_get_authtok failed.\n"));
                ret = LDAP_LOCAL_ERROR;
                goto done;
            }
        }

        ret = ldap_sasl_bind_s(ldap, user_dn, LDAP_SASL_SIMPLE, &password,
                               request_controls, NULL, NULL);
        if (ret != LDAP_SUCCESS) {
            DEBUG(1, ("ldap_sasl_bind_s failed (%d)[%s]\n", ret,
                      ldap_err2string(ret)));
        }
    } else {
        sasl_bind_state = talloc_zero(tmp_ctx, struct sasl_bind_state);
        if (sasl_bind_state == NULL) {
            DEBUG(1, ("talloc_zero failed.\n"));
            ret = LDAP_NO_MEMORY;
            goto done;
        }
        sasl_bind_state->sasl_user = dp_opt_get_string(p->opts->basic,
                                                      SDAP_SASL_AUTHID);
        ret = ldap_sasl_interactive_bind_s(ldap, NULL,
                                           sasl_mech, NULL, NULL,
                                           LDAP_SASL_QUIET,
                                           (*sdap_sasl_interact),
                                           sasl_bind_state);
        if (ret != LDAP_SUCCESS) {
            DEBUG(1, ("ldap_sasl_interactive_bind_s failed (%d)[%s]\n", ret,
                      ldap_err2string(ret)));
        }
    }

    DEBUG(7, ("%s bind to [%s].\n",
             (ret == LDAP_SUCCESS ? "Successfully" : "Failed to"), url));

done:
    talloc_free(tmp_ctx);

    return ret;
}