This patch appears to work. Note, I have only done superficial testing 
(checked that I can log in as a user who is in the specified group and that I 
can not log in as one that is not in this group). I have not tested this 
against AD, only OpenLDAP.

This patch applies to 2.2.17, but not to git-master.

        Guido
diff -rup jabberd-2.2.17-orig/etc/c2s.xml.dist.in jabberd-2.2.17/etc/c2s.xml.dist.in
--- jabberd-2.2.17-orig/etc/c2s.xml.dist.in	2012-05-22 22:27:51.000000000 +0200
+++ jabberd-2.2.17/etc/c2s.xml.dist.in	2012-12-12 16:39:54.490003311 +0100
@@ -546,6 +546,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 -rup jabberd-2.2.17-orig/storage/authreg_ldapfull.c jabberd-2.2.17/storage/authreg_ldapfull.c
--- jabberd-2.2.17-orig/storage/authreg_ldapfull.c	2012-02-19 14:23:09.000000000 +0100
+++ jabberd-2.2.17/storage/authreg_ldapfull.c	2012-12-12 16:52:30.400003587 +0100
@@ -68,6 +68,7 @@ typedef struct moddata_st
     char *objectclass;
     char *uidattr;
     char *validattr;
+    char *group_dn;
     char *pwattr;
     char *pwscheme;
 
@@ -583,6 +584,50 @@ retry:
     return dn;
 }
 
+/** Is this user part of the given LDAP group? */
+static int _ldapfull_user_in_group(moddata_t data, char *user_dn, 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;
+    }
+}
+
 /** do we have this user? */
 static int _ldapfull_find_user_dn(moddata_t data, char *username, char *realm, char **dn)
 {
@@ -601,6 +646,11 @@ static int _ldapfull_user_exists(authreg
 {
     char *dn;
     if (_ldapfull_find_user_dn((moddata_t) ar->private, username, realm, &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;
     }
@@ -748,22 +798,40 @@ static int _ldapfull_check_password(auth
 {
     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, char *username, char *realm) {
@@ -856,6 +924,8 @@ DLLEXPORT int ar_init(authreg_t ar)
     
     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";

Reply via email to