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";