minimal support for ldap groups

Wed, 15 Mar 2023 19:46:02 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 15 Mar 2023 19:46:02 +0100
changeset 471
9aa5ae3258f5
parent 470
467ed0f559af
child 472
d6bc67906c8c

minimal support for ldap groups

src/server/daemon/ldap_auth.c file | annotate | diff | comparison | revisions
src/server/daemon/ldap_auth.h file | annotate | diff | comparison | revisions
--- a/src/server/daemon/ldap_auth.c	Mon Mar 13 22:39:51 2023 +0100
+++ b/src/server/daemon/ldap_auth.c	Wed Mar 15 19:46:02 2023 +0100
@@ -327,6 +327,7 @@
                 }
             }
         }
+        
         if(uid_values[0].ptr) {
             // if we found a value for the first attribute, we can use that
             break;
@@ -335,6 +336,10 @@
         ldap_memfree(attribute);
         attribute = ldap_next_attribute(ldap, msg, ber); 
     }
+    if(ber) {
+        ber_free(ber, 0);
+    }
+        
 
     
     // use first value as uid
@@ -443,23 +448,104 @@
     return (User*)user;
 }
 
+
+static int is_member_attribute(LDAPAuthDB *auth, const char *attribute) {
+    LDAPConfig *config = &auth->config;
+    cxstring attr = cx_str(attribute);
+    for(int i=0;i<config->numMemberAttributes;i++) {
+        if(!cx_strcmp(config->memberAttributes[i], attr)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int group_add_member(LDAPGroup *group, LDAP *ldap, LDAPMessage *msg, char *attribute) {
+    struct berval **values = ldap_get_values_len(ldap, msg, attribute);
+    int ret = 0;
+    if(values) {
+        int count = ldap_count_values_len(values);
+        for(int i=0;i<count;i++) {
+            cxstring memberValue = cx_strn(values[i]->bv_val, values[i]->bv_len);
+            CxHashKey key = cx_hash_key(memberValue.ptr, memberValue.length);
+            char *g_member = cxMapGet(group->members, key);
+            if(!g_member) {
+                cxmutstr member = cx_strdup_a(group->members->allocator, memberValue);
+                if(!member.ptr) {
+                    ret = 1;
+                    break;
+                }
+                if(cxMapPut(group->members, key, member.ptr)) {
+                    ret = 1;
+                    break;
+                }
+            }
+        }
+        ldap_value_free_len(values);
+    }
+    return ret;
+}
+
+static LDAPGroup* ldap_msg_to_group(
+        Session *sn,
+        Request *rq,
+        LDAPAuthDB *authdb,
+        LDAP *ldap,
+        LDAPMessage *msg,
+        const char *group_name)
+{
+    CxAllocator *a = pool_allocator(sn->pool);
+    
+    LDAPGroup *group = pool_malloc(sn->pool, sizeof(LDAPGroup));
+    if(!group) {
+        return NULL;
+    }
+    group->members = cxHashMapCreate(a, 32);
+    if(!group->members) {
+        pool_free(sn->pool, group);
+        return NULL;
+    }
+    group->name = pool_strdup(sn->pool, group_name);
+    
+    BerElement *ber = NULL;
+    char *attribute = ldap_first_attribute(ldap, msg, &ber);
+    while(attribute) {
+        if(is_member_attribute(authdb, attribute)) {
+            if(group_add_member(group, ldap, msg, attribute)) {
+                // OOM
+                ldap_memfree(attribute);
+                // free at least some memory
+                cxMapDestroy(group->members);
+                pool_free(sn->pool, group);
+                group = NULL;
+                break;
+            }
+        }
+        
+        ldap_memfree(attribute);
+        attribute = ldap_next_attribute(ldap, msg, ber); 
+    }
+    if(ber) {
+        ber_free(ber, 0);
+    }
+    
+    return group;
+}
+
 LDAPGroup* ldap_get_group(Session *sn, Request *rq, LDAPAuthDB *authdb, const char *group) {
-    printf("ldap_get_group: %s\n", group);
-    
     LDAPConfig *config = &authdb->config;
+    CxAllocator *a = pool_allocator(sn->pool);
     
     LDAP *ld = get_ldap_session(sn, rq, authdb);
     if (ld == NULL) {
-        fprintf(stderr, "ldap_init failed\n");
         return NULL;
     }
     
-    // get the user dn
-    // TODO: use config for filter
-    // TODO: use asprintf
-    char filter[128];
-    int s = snprintf(filter, 127, "cn=%s", group);
-    filter[s] = 0;
+    cxstring groupSearch = cx_str(config->groupSearchFilter);
+    cxmutstr filter = cx_strreplace_a(a, groupSearch, cx_str("%s"), cx_str(group));
+    if(!filter.ptr) {
+        return NULL;
+    }
 
     LDAPMessage *result;
     struct timeval timeout;
@@ -469,22 +555,34 @@
             ld,
             config->basedn,
             LDAP_SCOPE_SUBTREE,
-            filter,
+            filter.ptr,
             NULL,
             0,
             NULL,        // server controls
             NULL,        // client controls
             &timeout,
-            1,           // size limit
+            2,           // size limit
             &result);
     if (r != LDAP_SUCCESS) {
-        //ws_ldap_close(ld);
-        
-        fprintf(stderr, "ldap_search_ext_s failed\n");
+        if(result) {
+            ldap_msgfree(result);
+        }
+        log_ereport(LOG_FAILURE, "ldap_get_group: search failed: %s", ldap_err2string(r));
         return NULL;
     }
     
+    LDAPMessage *msg = ldap_first_entry(ld, result);
     LDAPGroup *wsgroup = NULL;
+    if(msg) {
+        if(ldap_count_entries(ld, msg) > 1) {
+            log_ereport(LOG_FAILURE, "ldap_get_user: more than one search result");
+        } else {
+            wsgroup = ldap_msg_to_group(sn, rq, authdb, ld, msg, group);
+        }
+    }
+    ldap_msgfree(result);
+    
+    /*
     LDAPMessage *msg = ldap_first_entry(ld, result);
     if (msg) {
         // create group object
@@ -529,15 +627,14 @@
             ldap_memfree(attribute);
         }
     }
+    */
     
-    //ws_ldap_close(ld);
     return wsgroup;
 }
 
 int ldap_user_verify_password(User *u, const char *password) {
     LDAPUser *user = (LDAPUser*)u;
     
-    //int r = ldap_simple_bind_s(user->ldap, user->userdn, password);
     struct berval cred;
     cred.bv_val = (char*)password;
     cred.bv_len = strlen(password);
@@ -565,15 +662,13 @@
     int ret = 0;
     
     LDAPGroup *group = ldap_get_group(user->sn, user->rq, user->authdb, group_str);
-    for(int i=0;i<group->nmembers;i++) {
-        char *member = group->members[i].name;
-        if(!strcmp(member, u->name)) {
-            printf("is member\n");
+    if(group) {
+        char *member = cxMapGet(group->members, cx_hash_key_str(u->name));
+        if(member) {
             ret = 1;
         }
     }
-    
-    // TODO: free or cache group
+
     
     return ret;
 }
--- a/src/server/daemon/ldap_auth.h	Mon Mar 13 22:39:51 2023 +0100
+++ b/src/server/daemon/ldap_auth.h	Wed Mar 15 19:46:02 2023 +0100
@@ -170,10 +170,9 @@
 
 struct ldap_group {
     char        *name;
-    LDAPMember  *members;
-    size_t      nmembers;
+    char        *dn;
+    CxMap       *members; 
     time_t      update;
-    LDAPGroup   *next;
 };
 
 /*

mercurial