[sssd] Add plugin for cifs-utils

sbose sbose at fedoraproject.org
Tue Oct 15 10:34:10 UTC 2013


commit df4dbc81ab3fc741c90f46a43a04878946affe82
Author: Sumit Bose <sbose at redhat.com>
Date:   Tue Oct 15 12:35:12 2013 +0200

    Add plugin for cifs-utils
    
    - Resolves: rhbz#998544

 ...dle-SID-requests-if-noexist_delete-is-set.patch |   41 ++
 0602-FEDORA-Add-CIFS-idmap-plugin.patch            |  493 ++++++++++++++++++++
 sssd.spec                                          |   38 ++-
 3 files changed, 570 insertions(+), 2 deletions(-)
---
diff --git a/0601-FEDORA-LDAP-handle-SID-requests-if-noexist_delete-is-set.patch b/0601-FEDORA-LDAP-handle-SID-requests-if-noexist_delete-is-set.patch
new file mode 100644
index 0000000..e088d0d
--- /dev/null
+++ b/0601-FEDORA-LDAP-handle-SID-requests-if-noexist_delete-is-set.patch
@@ -0,0 +1,41 @@
+From f244195582ec804f1022341e2e3394754e31b36a Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose at redhat.com>
+Date: Wed, 9 Oct 2013 18:19:08 +0200
+Subject: [PATCH] LDAP: handle SID requests if noexist_delete is set
+
+Fixes https://fedorahosted.org/sssd/ticket/2116
+---
+ src/providers/ldap/ldap_id.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
+index 162d987..59dfd0a 100644
+--- a/src/providers/ldap/ldap_id.c
++++ b/src/providers/ldap/ldap_id.c
+@@ -365,6 +365,11 @@ static void users_get_done(struct tevent_req *subreq)
+             }
+             break;
+ 
++        case BE_FILTER_SECID:
++            /* Since it is not clear if the SID belongs to a user or a group
++             * we have nothing to do here. */
++            break;
++
+         default:
+             tevent_req_error(req, EINVAL);
+             return;
+@@ -694,6 +699,11 @@ static void groups_get_done(struct tevent_req *subreq)
+             }
+             break;
+ 
++        case BE_FILTER_SECID:
++            /* Since it is not clear if the SID belongs to a user or a group
++             * we have nothing to do here. */
++            break;
++
+         default:
+             tevent_req_error(req, EINVAL);
+             return;
+-- 
+1.8.3.1
+
diff --git a/0602-FEDORA-Add-CIFS-idmap-plugin.patch b/0602-FEDORA-Add-CIFS-idmap-plugin.patch
new file mode 100644
index 0000000..af090fa
--- /dev/null
+++ b/0602-FEDORA-Add-CIFS-idmap-plugin.patch
@@ -0,0 +1,493 @@
+From 15b3f9012309ca1c10528139946523bc295a4a9b Mon Sep 17 00:00:00 2001
+From: Benjamin Franzke <benjaminfranzke at googlemail.com>
+Date: Thu, 26 Sep 2013 10:27:33 +0200
+Subject: [PATCH] Add CIFS idmap plugin
+
+https://fedorahosted.org/sssd/ticket/1534
+---
+ Makefile.am                             |  21 ++
+ configure.ac                            |   2 +
+ src/conf_macros.m4                      |  14 ++
+ src/external/cifsidmap.m4               |  16 ++
+ src/lib/cifs_idmap_sss/cifs_idmap_sss.c | 340 ++++++++++++++++++++++++++++++++
+ src/tests/dlopen-tests.c                |   3 +
+ 6 files changed, 396 insertions(+)
+ create mode 100644 src/external/cifsidmap.m4
+ create mode 100644 src/lib/cifs_idmap_sss/cifs_idmap_sss.c
+
+diff --git a/Makefile.am b/Makefile.am
+index 15c92d9..cb24df8 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -32,6 +32,9 @@ endif
+ if BUILD_PAC_RESPONDER
+ krb5authdata_plugindir = @krb5authdatapluginpath@
+ endif
++if BUILD_CIFS_IDMAP_PLUGIN
++cifsplugindir = @cifspluginpath@
++endif
+ sssdconfdir = $(sysconfdir)/sssd
+ sssddatadir = $(datadir)/sssd
+ sssdapiplugindir = $(sssddatadir)/sssd.api.d
+@@ -193,6 +196,11 @@ krb5authdata_plugin_LTLIBRARIES = \
+     sssd_pac_plugin.la
+ endif
+ 
++if BUILD_CIFS_IDMAP_PLUGIN
++cifsplugin_LTLIBRARIES = \
++    cifs_idmap_sss.la
++endif
++
+ noinst_LTLIBRARIES =
+ 
+ pkglib_LTLIBRARIES = \
+@@ -1896,6 +1904,19 @@ pysss_nss_idmap_la_LDFLAGS = \
+     -module
+ endif
+ 
++if BUILD_CIFS_IDMAP_PLUGIN
++cifs_idmap_sss_la_SOURCES = \
++    src/lib/cifs_idmap_sss/cifs_idmap_sss.c
++cifs_idmap_sss_la_LIBADD = \
++    libsss_idmap.la \
++    libsss_nss_idmap.la
++cifs_idmap_sss_la_CFLAGS = \
++    $(AM_CFLAGS)
++cifs_idmap_sss_la_LDFLAGS = \
++    -avoid-version \
++    -module
++endif
++
+ ################
+ # TRANSLATIONS #
+ ################
+diff --git a/configure.ac b/configure.ac
+index d28d55f..9934b50 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -115,6 +115,7 @@ WITH_KRB5_RCACHE_DIR
+ WITH_KRB5AUTHDATA_PLUGIN_PATH
+ WITH_KRB5_CONF
+ WITH_PYTHON_BINDINGS
++WITH_CIFS_PLUGIN_PATH
+ WITH_SELINUX
+ WITH_NSCD
+ WITH_SEMANAGE
+@@ -153,6 +154,7 @@ m4_include([src/external/libkeyutils.m4])
+ m4_include([src/external/libnl.m4])
+ m4_include([src/external/systemd.m4])
+ m4_include([src/external/pac_responder.m4])
++m4_include([src/external/cifsidmap.m4])
+ m4_include([src/external/signal.m4])
+ m4_include([src/external/inotify.m4])
+ m4_include([src/external/libndr_nbt.m4])
+diff --git a/src/conf_macros.m4 b/src/conf_macros.m4
+index 1aecaea..4be819d 100644
+--- a/src/conf_macros.m4
++++ b/src/conf_macros.m4
+@@ -265,6 +265,20 @@ AC_DEFUN([WITH_KRB5_PLUGIN_PATH],
+     AC_SUBST(krb5pluginpath)
+   ])
+ 
++AC_DEFUN([WITH_CIFS_PLUGIN_PATH],
++  [ AC_ARG_WITH([cifs-plugin-path],
++                [AC_HELP_STRING([--with-cifs-plugin-path=PATH],
++                                [Path to cifs-utils plugin store [/usr/lib/cifs-utils]]
++                               )
++                ]
++               )
++    cifspluginpath="${libdir}/cifs-utils"
++    if test x"$with_cifs_plugin_path" != x; then
++        cifspluginpath=$with_cifs_plugin_path
++    fi
++    AC_SUBST(cifspluginpath)
++  ])
++
+ AC_DEFUN([WITH_KRB5_RCACHE_DIR],
+   [ AC_ARG_WITH([krb5-rcache-dir],
+                 [AC_HELP_STRING([--with-krb5-rcache-dir=PATH],
+diff --git a/src/external/cifsidmap.m4 b/src/external/cifsidmap.m4
+new file mode 100644
+index 0000000..53cb8b7
+--- /dev/null
++++ b/src/external/cifsidmap.m4
+@@ -0,0 +1,16 @@
++AC_ARG_ENABLE([cifs-idmap-plugin],
++              [AS_HELP_STRING([--disable-cifs-idmap-plugin],
++                              [do not build CIFS idmap plugin])],
++              [build_cifs_idmap_plugin=$enableval],
++              [build_cifs_idmap_plugin=yes])
++
++AS_IF([test x$build_cifs_idmap_plugin = xyes],
++      [AC_CHECK_HEADER([cifsidmap.h], [],
++                       [AC_MSG_ERROR([you must have the cifsidmap header installed to build the idmap plugin])])
++      ])
++
++AM_CONDITIONAL([BUILD_CIFS_IDMAP_PLUGIN],
++               [test x$build_cifs_idmap_plugin = xyes])
++
++AM_COND_IF([BUILD_CIFS_IDMAP_PLUGIN],
++           [AC_DEFINE_UNQUOTED(HAVE_CIFS_IDMAP_PLUGIN, 1, [Build with cifs idmap plugin])])
+diff --git a/src/lib/cifs_idmap_sss/cifs_idmap_sss.c b/src/lib/cifs_idmap_sss/cifs_idmap_sss.c
+new file mode 100644
+index 0000000..f914917
+--- /dev/null
++++ b/src/lib/cifs_idmap_sss/cifs_idmap_sss.c
+@@ -0,0 +1,340 @@
++/*
++    Authors:
++        Benjamin Franzke <benjaminfranzke at googlemail.com>
++
++    Copyright (C) 2013 Benjamin Franzke
++
++    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/>.
++*/
++
++/* TODO: Support well known SIDs as in samba's
++ *        - librpc/idl/security.idl or
++ *        - source4/rpc_server/lsa/lsa_lookup.c?
++ */
++
++/* TODO: Support of [all] samba's Unix SIDs:
++ *         Users:  S-1-22-1-%UID
++ *         Groups: S-1-22-2-%GID
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <limits.h>
++#include <stdarg.h>
++
++#include <cifsidmap.h>
++
++#include "lib/idmap/sss_idmap.h"
++#include "sss_client/idmap/sss_nss_idmap.h"
++
++#define WORLD_SID "S-1-1-0"
++
++#ifdef DEBUG
++#include <syslog.h>
++#define debug(str, ...) \
++    syslog(0, "%s: " str "\n", \
++           __FUNCTION__, ##__VA_ARGS__)
++#else
++#define debug(...) do { } while(0)
++#endif
++
++struct sssd_ctx {
++    struct sss_idmap_ctx *idmap;
++    const char **errmsg;
++};
++
++#define ctx_set_error(ctx, error) \
++    do { \
++        *ctx->errmsg = error; \
++        debug("%s", error ? error : ""); \
++    } while (0);
++
++int cifs_idmap_init_plugin(void **handle, const char **errmsg)
++{
++    struct sssd_ctx *ctx;
++    enum idmap_error_code err;
++
++    if (handle == NULL || errmsg == NULL)
++        return EINVAL;
++
++    ctx = malloc(sizeof *ctx);
++    if (!ctx) {
++        *errmsg = "Failed to allocate context";
++        return -1;
++    }
++    ctx->errmsg = errmsg;
++    ctx_set_error(ctx, NULL);
++
++    err = sss_idmap_init(NULL, NULL, NULL, &ctx->idmap);
++    if (err != IDMAP_SUCCESS) {
++        ctx_set_error(ctx, idmap_error_string(err));
++        free(ctx);
++        return -1;
++    }
++
++    *handle = ctx;
++    return 0;
++}
++
++void cifs_idmap_exit_plugin(void *handle)
++{
++    struct sssd_ctx *ctx = handle;
++
++    debug("exit");
++
++    if (ctx == NULL)
++        return;
++
++    sss_idmap_free(ctx->idmap);
++
++    free(ctx);
++}
++
++
++/* Test with `getcifsacl file` on client. */
++int cifs_idmap_sid_to_str(void *handle, const struct cifs_sid *csid,
++                          char **name)
++{
++    struct sssd_ctx *ctx = handle;
++    enum idmap_error_code iderr;
++    char *sid;
++    enum sss_id_type id_type;
++    int err;
++
++    iderr = sss_idmap_bin_sid_to_sid(ctx->idmap, (const uint8_t *) csid,
++                                     sizeof(*csid), &sid);
++    if (iderr != IDMAP_SUCCESS) {
++        ctx_set_error(ctx, idmap_error_string(iderr));
++        *name = NULL;
++        return -1;
++    }
++
++    debug("sid: %s", sid);
++
++    if (strcmp(sid, WORLD_SID) == 0) {
++        *name = strdup("\\Everyone");
++        if (!*name) {
++            ctx_set_error(ctx, strerror(ENOMEM));
++            return ENOMEM;
++        }
++        return 0;
++    }
++
++    err = sss_nss_getnamebysid(sid, name, &id_type);
++    if (err != 0)  {
++        ctx_set_error(ctx, strerror(err));
++        *name = NULL;
++        return -err;
++    }
++
++    /* FIXME: Map Samba Unix SIDs? (sid->id and use getpwuid)? */
++
++    debug("name: %s", *name);
++
++    return 0;
++}
++
++static int sid_to_cifs_sid(struct sssd_ctx *ctx, const char *sid,
++                           struct cifs_sid *csid)
++{
++    uint8_t *bsid = NULL;
++    enum idmap_error_code err;
++    size_t length;
++
++    err = sss_idmap_sid_to_bin_sid(ctx->idmap,
++                                   sid, &bsid, &length);
++    if (err != IDMAP_SUCCESS) {
++        ctx_set_error(ctx, idmap_error_string(err));
++        return -1;
++    }
++    if (length > sizeof(struct cifs_sid)) {
++        ctx_set_error(ctx, "too large sid length");
++        free(bsid);
++        return -1;
++    }
++
++    memcpy(csid, bsid, length);
++    free(bsid);
++
++    return 0;
++}
++
++/* Test with setcifsacl -a */
++int cifs_idmap_str_to_sid(void *handle, const char *name,
++                          struct cifs_sid *csid)
++{
++    struct sssd_ctx *ctx = handle;
++    int err;
++    enum sss_id_type id_type;
++    char *sid = NULL;
++    int success = 0;
++
++    debug("%s", name);
++
++    err = sss_nss_getsidbyname(name, &sid, &id_type);
++    if (err != 0)  {
++        /* Might be a raw string representation of SID,
++         * try converting that before returning an error. */
++        if (sid_to_cifs_sid(ctx, name, csid) == 0)
++            return 0;
++
++        ctx_set_error(ctx, strerror(err));
++        return -err;
++    }
++
++    if (sid_to_cifs_sid(ctx, sid, csid) != 0)
++        success = -1;
++
++    free(sid);
++
++    return success;
++}
++
++static int samba_unix_sid_to_id(const char *sid, struct cifs_uxid *cuxid)
++{
++    id_t id;
++    uint8_t type;
++
++    if (sscanf(sid, "S-1-22-%hhu-%u", &type, &id) != 2)
++        return -1;
++
++    switch (type) {
++    case 1:
++        cuxid->type = CIFS_UXID_TYPE_UID;
++        cuxid->id.uid = id;
++        break;
++    case 2:
++        cuxid->type = CIFS_UXID_TYPE_GID;
++        cuxid->id.gid = id;
++        break;
++    default:
++        cuxid->type = CIFS_UXID_TYPE_UNKNOWN;
++        return -1;
++    }
++
++    return 0;
++}
++
++static int sss_sid_to_id(struct sssd_ctx *ctx, const char *sid,
++                         struct cifs_uxid *cuxid)
++{
++    int err;
++    enum sss_id_type id_type;
++
++    err = sss_nss_getidbysid(sid, (uint32_t *)&cuxid->id.uid, &id_type);
++    if (err != 0)  {
++        ctx_set_error(ctx, strerror(err));
++        return -1;
++    }
++
++    switch (id_type) {
++    case SSS_ID_TYPE_UID:
++        cuxid->type = CIFS_UXID_TYPE_UID;
++        break;
++    case SSS_ID_TYPE_GID:
++        cuxid->type = CIFS_UXID_TYPE_GID;
++        break;
++    case SSS_ID_TYPE_BOTH:
++        cuxid->type = CIFS_UXID_TYPE_BOTH;
++        break;
++    case SSS_ID_TYPE_NOT_SPECIFIED:
++    default:
++        return -1;
++    }
++
++    return 0;
++}
++
++/**
++ * cifs_idmap_sids_to_ids - convert struct cifs_sids to struct cifs_uxids
++ * usecase: mount.cifs -o sec=krb5,multiuser,cifsacl,nounix
++ * test: ls -n on mounted share
++ */
++int cifs_idmap_sids_to_ids(void *handle, const struct cifs_sid *csid,
++                           const size_t num, struct cifs_uxid *cuxid)
++{
++    struct sssd_ctx *ctx = handle;
++    enum idmap_error_code err;
++    int success = -1;
++    size_t i;
++    char *sid;
++
++    debug("num: %zd", num);
++
++    if (num > UINT_MAX) {
++        ctx_set_error(ctx, "num is too large.");
++        return EINVAL;
++    }
++
++    for (i = 0; i < num; ++i) {
++        err = sss_idmap_bin_sid_to_sid(ctx->idmap, (const uint8_t *) &csid[i],
++                                       sizeof(csid[i]), &sid);
++        if (err != IDMAP_SUCCESS) {
++            ctx_set_error(ctx, idmap_error_string(err));
++            continue;
++        }
++
++        cuxid[i].type = CIFS_UXID_TYPE_UNKNOWN;
++
++        if (sss_sid_to_id(ctx, sid, &cuxid[i]) == 0 ||
++            samba_unix_sid_to_id(sid, &cuxid[i]) == 0) {
++
++            debug("setting uid of %s to %d", sid, cuxid[i].id.uid);
++            success = 0;
++        }
++
++        free(sid);
++    }
++
++    return success;
++}
++
++
++int cifs_idmap_ids_to_sids(void *handle, const struct cifs_uxid *cuxid,
++                           const size_t num, struct cifs_sid *csid)
++{
++    struct sssd_ctx *ctx = handle;
++    int err, success = -1;
++    char *sid;
++    enum sss_id_type id_type;
++    size_t i;
++
++    debug("num ids: %zd", num);
++
++    if (num > UINT_MAX) {
++        ctx_set_error(ctx, "num is too large.");
++        return EINVAL;
++    }
++
++    for (i = 0; i < num; ++i) {
++        err = sss_nss_getsidbyid((uint32_t)cuxid[i].id.uid, &sid, &id_type);
++        if (err != 0)  {
++            ctx_set_error(ctx, strerror(err));
++            csid[i].revision = 0;
++            /* FIXME: would it be safe to map *any* uid/gids unknown by sssd to
++             * SAMBA's UNIX SIDs? */
++            continue;
++        }
++
++        if (sid_to_cifs_sid(ctx, sid, csid) == 0)
++            success = 0;
++        else
++            csid[i].revision = 0;
++        free(sid);
++    }
++
++    return success;
++}
+diff --git a/src/tests/dlopen-tests.c b/src/tests/dlopen-tests.c
+index 67fc41c..40e02da 100644
+--- a/src/tests/dlopen-tests.c
++++ b/src/tests/dlopen-tests.c
+@@ -56,6 +56,9 @@ struct so {
+ #ifdef HAVE_PAC_RESPONDER
+     { "sssd_pac_plugin.so", { LIBPFX"sssd_pac_plugin.so", NULL } },
+ #endif
++#ifdef HAVE_CIFS_IDMAP_PLUGIN
++    { "cifs_idmap_sss.so", { LIBPFX"cifs_idmap_sss.so", NULL } },
++#endif
+     { "memberof.so", { LIBPFX"memberof.so", NULL } },
+     { "libsss_child.so", { "libtevent.so",
+                            LIBPFX"libsss_debug.so",
+-- 
+1.8.3.1
+
diff --git a/sssd.spec b/sssd.spec
index 1483857..0bd404f 100644
--- a/sssd.spec
+++ b/sssd.spec
@@ -2,13 +2,19 @@
 %define __provides_exclude_from %{python_sitearch}/.*\.so$
 %define _hardened_build 1
 
+%if (0%{?fedora} >= 17 || 0%{?rhel} >= 7)
+    %global with_cifs_utils_plugin 1
+%else
+    %global with_cifs_utils_plugin_option --disable-cifs-idmap-plugin
+%endif
+
 # Determine the location of the LDB modules directory
 %global ldb_modulesdir %(pkg-config --variable=modulesdir ldb)
 %global ldb_version 1.1.16
 
 Name: sssd
 Version: 1.11.1
-Release: 3%{?dist}
+Release: 4%{?dist}
 Group: Applications/System
 Summary: System Security Services Daemon
 License: GPLv3+
@@ -21,6 +27,9 @@ Patch0001: 0001-krb5-Remove-ability-to-create-public-directories.patch
 Patch0002: 0002-krb5-Fix-unit-tests.patch
 Patch0003: 0003-AD-properly-intitialize-GC-from-ad_server-option.patch
 
+Patch0601:  0601-FEDORA-LDAP-handle-SID-requests-if-noexist_delete-is-set.patch
+Patch0602:  0602-FEDORA-Add-CIFS-idmap-plugin.patch
+
 ### Dependencies ###
 Requires: sssd-common = %{version}-%{release}
 Requires: sssd-ldap = %{version}-%{release}
@@ -82,6 +91,9 @@ BuildRequires: selinux-policy-targeted
 %ifarch %{ix86} x86_64 %{arm}
 BuildRequires: libcmocka-devel
 %endif
+%if (0%{?with_cifs_utils_plugin} == 1)
+BuildRequires: cifs-utils-devel
+%endif
 
 %description
 Provides a set of daemons to manage access to remote directories and
@@ -130,6 +142,8 @@ Group: Applications/System
 License: LGPLv3+
 Requires(post): /sbin/ldconfig
 Requires(postun): /sbin/ldconfig
+Requires(post):  /usr/sbin/alternatives
+Requires(preun): /usr/sbin/alternatives
 
 %description client
 Provides the libraries needed by the PAM and NSS stacks to connect to the SSSD
@@ -370,7 +384,8 @@ autoreconf -ivf
     --enable-ldb-version-check \
     --disable-static \
     --disable-rpath \
-    --with-test-dir=/dev/shm
+    --with-test-dir=/dev/shm \
+    %{?with_cifs_utils_plugin_option}
 
 make %{?_smp_mflags} all docs
 
@@ -599,6 +614,10 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/security/pam_sss.so
 %{_libdir}/krb5/plugins/libkrb5/sssd_krb5_locator_plugin.so
 %{_libdir}/krb5/plugins/authdata/sssd_pac_plugin.so
+%if (0%{?with_cifs_utils_plugin} == 1)
+%{_libdir}/cifs-utils/cifs_idmap_sss.so
+%ghost %{_sysconfdir}/cifs-utils/idmap-plugin
+%endif
 %{_mandir}/man8/pam_sss.8*
 %{_mandir}/man8/sssd_krb5_locator_plugin.8*
 
@@ -694,7 +713,18 @@ if [ $1 -ge 1 ] ; then
     /bin/systemctl try-restart sssd.service >/dev/null 2>&1 || :
 fi
 
+%if (0%{?with_cifs_utils_plugin} == 1)
+%post client
+/sbin/ldconfig
+/usr/sbin/alternatives --install /etc/cifs-utils/idmap-plugin cifs-idmap-plugin %{_libdir}/cifs-utils/cifs_idmap_sss.so 20
+
+%preun client
+if [ $1 -eq 0 ]; then
+        /usr/sbin/alternatives --remove cifs-idmap-plugin %{_libdir}/cifs-utils/cifs_idmap_sss.so
+fi
+%else
 %post client -p /sbin/ldconfig
+%endif
 
 %postun client -p /sbin/ldconfig
 
@@ -707,6 +737,10 @@ fi
 %postun -n libsss_idmap -p /sbin/ldconfig
 
 %changelog
+* Mon Oct 14 2013 Sumit Bose <sbose at redhat.com> - 1.11.1-4
+- Add plugin for cifs-utils
+- Resolves: rhbz#998544
+
 * Tue Oct 08 2013 Jakub Hrozek <jhrozek at redhat.com> - 1.11.1-3
 - Fix failover from Global Catalog to LDAP in case GC is not available
 


More information about the scm-commits mailing list