Wed, 15 Mar 2023 19:46:02 +0100
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; }