The same patch for git master.
>From 559475a60dbe5a793f2632f5abb723ec19bedc07 Mon Sep 17 00:00:00 2001
From: Guido Winkelmann <[email protected]>
Date: Thu, 13 Dec 2012 00:57:10 +0100
Subject: [PATCH] ldapfull: Check for ldap group membership on login

Administrators can now supply a <group_dn> configuration directive. If
it is given, only users who are members of this group will be allowed to login
---
 etc/c2s.xml.dist.in        |    9 +++++
 storage/authreg_ldapfull.c |   82 ++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 85 insertions(+), 6 deletions(-)

diff --git a/etc/c2s.xml.dist.in b/etc/c2s.xml.dist.in
index eb402d5..6626b43 100644
--- a/etc/c2s.xml.dist.in
+++ b/etc/c2s.xml.dist.in
@@ -563,6 +563,15 @@
       <!--
       <validattr>valid</validattr>
       -->
+
+      <!-- Group that users must be members of
+           If this is set, only user that are members of the specified LDAP
+           group can log in. The group must be specified with its full
+           distinguished name -->
+      <!--
+      <group_dn>cn=jabberdusers,ou=servicegroups,dc=example,dc=com</group_dn>
+      -->
+
       <fulluid/>
       <!-- If pwscheme is not defined, then passwords are stored in clear
            text and digest authentication may be done.
diff --git a/storage/authreg_ldapfull.c b/storage/authreg_ldapfull.c
index b651dce..5149b29 100644
--- a/storage/authreg_ldapfull.c
+++ b/storage/authreg_ldapfull.c
@@ -68,6 +68,7 @@ typedef struct moddata_st
     const char *objectclass;
     const char *uidattr;
     const char *validattr;
+    const char *group_dn;
     const char *pwattr;
     const char *pwscheme;
 
@@ -585,7 +586,51 @@ retry:
     return dn;
 }
 
-/** do we have this user? */
+/** Is this user part of the given LDAP group? */
+static int _ldapfull_user_in_group(moddata_t data, const char *user_dn, const char *group_dn)
+{
+    LDAPMessage *result, *entry;
+    int tried = 0;
+    char filter[1024];
+
+    log_debug(ZONE, "checking whether user with dn %s is in group %s", user_dn, group_dn);
+
+    memset(filter, 0, 1024);
+    snprintf(filter, 1024, "(member=%s)", user_dn); // TODO Check if snprintf result was truncated
+
+    retry:
+    if(ldap_search_s(data->ld, group_dn, LDAP_SCOPE_BASE, filter, NULL, 0, &result))
+    {
+        if( tried++ < LDAPFULL_SEARCH_MAX_RETRIES ) {
+            log_debug(ZONE, "ldap: group search fail, will retry; %s: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
+            _ldapfull_unbind(data);
+            if( _ldapfull_connect_bind(data) == 0 ) {
+                goto retry;
+            } else {
+                return 0;
+            }
+        }
+        log_write(data->ar->c2s->log, LOG_ERR, "ldap: group search %s failed: %s", filter, ldap_err2string(_ldapfull_get_lderrno(data->ld)));
+        _ldapfull_unbind(data);
+        return 0;
+    }
+
+    entry = ldap_first_entry(data->ld, result);
+    if(entry == NULL)
+    {
+        ldap_msgfree(result);
+
+        return 0;
+    }
+    else
+    {
+        ldap_msgfree(result);
+
+        return 1;
+    }
+}
+
+/** Get distinguished name for this user if we have it */
 static int _ldapfull_find_user_dn(moddata_t data, const char *username, const char *realm, const char **dn)
 {
     *dn = NULL;
@@ -603,7 +648,12 @@ static int _ldapfull_user_exists(authreg_t ar, const char *username, const char
 {
     const char *dn;
     if (_ldapfull_find_user_dn((moddata_t) ar->private, username, realm, &dn)) {
-        ldap_memfree((void*)dn);
+        if(((moddata_t) ar->private)->group_dn != NULL
+            && !_ldapfull_user_in_group((moddata_t) ar->private, dn, ((moddata_t) ar->private)->group_dn)) {
+            ldap_memfree(dn);
+            return 0;
+            }
+        ldap_memfree(dn);
         return 1;
     }
     return 0;
@@ -751,22 +801,40 @@ static int _ldapfull_check_password(authreg_t ar, const char *username, const ch
 {
     moddata_t data = (moddata_t) ar->private;
     char buf[LDAPFULL_PASSBUF_MAX];
+    char *dn;
 
     log_debug(ZONE, "checking password for %s", username);
 
     if(password[0] == '\0')
         return 1;
 
+    if(data->group_dn != NULL) {
+        if (!_ldapfull_find_user_dn(data, username, realm, &dn))
+            return 1;
+    }
     /* The bind scheme doesn't need the password read first, so short circuit
        the whole passhash scheme */
-    if (!strcmp(data->pwscheme, "bind"))
-        return _ldapfull_check_password_bind(ar, username, realm, password);
+    if (!strcmp(data->pwscheme, "bind")) {
+        if(_ldapfull_check_password_bind(ar, username, realm, password) == 0) {
+            if(data->group_dn != NULL && !_ldapfull_user_in_group(data, dn, data->group_dn))
+                return 1;
+            else
+                return 0;
+        }
+    }
 
     if( _ldapfull_get_password(ar,username,realm,buf) != 0  ) {
         return 1;
     }
 
-    return ! _ldapfull_check_passhash(data,buf,password);
+    if(_ldapfull_check_passhash(data,buf,password)){
+        if(data->group_dn != NULL && !_ldapfull_user_in_group(data, dn, data->group_dn))
+            return 1;
+        else
+            return 0;
+    }
+    else
+        return 1;
 }
 
 static int _ldapfull_create_user(authreg_t ar, const char *username, const char *realm) {
@@ -856,9 +924,11 @@ DLLEXPORT int ar_init(authreg_t ar)
     data->uidattr = config_get_one(ar->c2s->config, "authreg.ldapfull.uidattr", 0);
     if(data->uidattr == NULL)
         data->uidattr = "uid";
-    
+
     data->validattr = config_get_one(ar->c2s->config, "authreg.ldapfull.validattr", 0);
 
+    data->group_dn = config_get_one(ar->c2s->config, "authreg.ldapfull.group_dn", 0);
+
     data->pwattr = config_get_one(ar->c2s->config, "authreg.ldapfull.pwattr", 0);
     if(data->pwattr == NULL)
         data->pwattr = "jabberPassword";
-- 
1.7.8.6

Reply via email to