]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Skip LDAP group processing on suspension
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 23 Feb 2024 22:36:12 +0000 (15:36 -0700)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 23 Feb 2024 22:36:12 +0000 (15:36 -0700)
raddb/mods-available/ldap
src/modules/rlm_ldap/groups.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_ldap/rlm_ldap.h
src/modules/rlm_ldap/user.c

index 76ffbe57603104abc7c561d584ba557f33f48f0e..b68260426d836b3a0be19d5f8eb7d05c1c81db43 100644 (file)
@@ -476,6 +476,14 @@ ldap {
                #  `(<inst>-Group` or `LDAP-Group` if using the default instance).
                #
                group_attribute = "${..:instance}-Group"
+
+               #
+               #  skip_on_suspend::
+               #
+               #  Don't process user groups if the user has been suspended.
+               #  If set to 'no', groups will still be processed.
+               #
+               skip_on_suspend = 'yes'
        }
 
        #
index 2f342e1a86b49077515ba7adaf1bc9b7ba3c4931..e7dbcb9dc36f07b1546d94e6941e662bc4a1236b 100644 (file)
@@ -29,7 +29,6 @@ RCSID("$Id$")
 USES_APPLE_DEPRECATED_API
 
 #include <freeradius-devel/util/debug.h>
-#include <ctype.h>
 
 #define LOG_PREFIX "rlm_ldap groups"
 
@@ -117,7 +116,7 @@ static unlang_action_t ldap_group_name2dn_start(rlm_rcode_t *p_result, UNUSED in
        char                            buffer[LDAP_MAX_GROUP_NAME_LEN + 1];
        char                            *filter;
 
-       if (!inst->groupobj_name_attr) {
+       if (!inst->group.obj_name_attr) {
                REDEBUG("Told to convert group names to DNs but missing 'group.name_attribute' directive");
                RETURN_MODULE_INVALID;
        }
@@ -133,21 +132,21 @@ static unlang_action_t ldap_group_name2dn_start(rlm_rcode_t *p_result, UNUSED in
         *      for the entire group list at once.
         */
        filter = talloc_typed_asprintf(group_ctx, "%s%s%s",
-                                inst->groupobj_filter ? "(&" : "",
-                                inst->groupobj_filter ? inst->groupobj_filter : "",
+                                inst->group.obj_filter ? "(&" : "",
+                                inst->group.obj_filter ? inst->group.obj_filter : "",
                                 group_ctx->group_name[0] && group_ctx->group_name[1] ? "(|" : "");
        while (*name) {
                fr_ldap_uri_escape_func(request, buffer, sizeof(buffer), *name++, NULL);
-               filter = talloc_asprintf_append_buffer(filter, "(%s=%s)", inst->groupobj_name_attr, buffer);
+               filter = talloc_asprintf_append_buffer(filter, "(%s=%s)", inst->group.obj_name_attr, buffer);
 
                group_ctx->name_cnt++;
        }
        filter = talloc_asprintf_append_buffer(filter, "%s%s",
-                                              inst->groupobj_filter ? ")" : "",
+                                              inst->group.obj_filter ? ")" : "",
                                               group_ctx->group_name[0] && group_ctx->group_name[1] ? ")" : "");
 
        return fr_ldap_trunk_search(group_ctx, &group_ctx->query, request, group_ctx->ttrunk,
-                                   group_ctx->base_dn->vb_strvalue, inst->groupobj_scope, filter,
+                                   group_ctx->base_dn->vb_strvalue, inst->group.obj_scope, filter,
                                    null_attrs, NULL, NULL);
 }
 
@@ -220,7 +219,7 @@ static unlang_action_t ldap_group_name2dn_resume(rlm_rcode_t *p_result, UNUSED i
                fr_ldap_util_normalise_dn(dn, dn);
 
                RDEBUG2("Got group DN \"%s\"", dn);
-               MEM(vp = fr_pair_afrom_da(group_ctx->list_ctx, inst->cache_da));
+               MEM(vp = fr_pair_afrom_da(group_ctx->list_ctx, inst->group.cache_da));
                fr_pair_value_bstrndup(vp, dn, strlen(dn), true);
                fr_pair_append(&group_ctx->groups, vp);
                ldap_memfree(dn);
@@ -254,7 +253,7 @@ static unlang_action_t ldap_group_dn2name_start(rlm_rcode_t *p_result, UNUSED in
        ldap_group_userobj_ctx_t        *group_ctx = talloc_get_type_abort(uctx, ldap_group_userobj_ctx_t);
        rlm_ldap_t const                *inst = group_ctx->inst;
 
-       if (!inst->groupobj_name_attr) {
+       if (!inst->group.obj_name_attr) {
                REDEBUG("Told to resolve group DN to name but missing 'group.name_attribute' directive");
                RETURN_MODULE_INVALID;
        }
@@ -295,7 +294,7 @@ static unlang_action_t ldap_group_dn2name_resume(rlm_rcode_t *p_result, UNUSED i
        case LDAP_RESULT_NO_RESULT:
        case LDAP_RESULT_BAD_DN:
                REDEBUG("Group DN \"%s\" did not resolve to an object", *group_ctx->dn);
-               rcode = (inst->allow_dangling_group_refs ? RLM_MODULE_NOOP : RLM_MODULE_INVALID);
+               rcode = (inst->group.allow_dangling_refs ? RLM_MODULE_NOOP : RLM_MODULE_INVALID);
                goto finish;
 
        default:
@@ -311,14 +310,14 @@ static unlang_action_t ldap_group_dn2name_resume(rlm_rcode_t *p_result, UNUSED i
                goto finish;
        }
 
-       values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->groupobj_name_attr);
+       values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->group.obj_name_attr);
        if (!values) {
-               REDEBUG("No %s attributes found in object", inst->groupobj_name_attr);
+               REDEBUG("No %s attributes found in object", inst->group.obj_name_attr);
                rcode = RLM_MODULE_INVALID;
                goto finish;
        }
 
-       MEM(vp = fr_pair_afrom_da(group_ctx->list_ctx, inst->cache_da));
+       MEM(vp = fr_pair_afrom_da(group_ctx->list_ctx, inst->group.cache_da));
        fr_pair_value_bstrndup(vp, values[0]->bv_val, values[0]->bv_len, true);
        fr_pair_append(&group_ctx->groups, vp);
        RDEBUG2("Group DN \"%s\" resolves to name \"%pV\"", *group_ctx->dn, &vp->data);
@@ -358,7 +357,7 @@ static unlang_action_t ldap_cacheable_userobj_store(rlm_rcode_t *p_result, reque
                for (vp = fr_pair_list_head(&group_ctx->groups);
                     vp;
                     vp = fr_pair_list_next(&group_ctx->groups, vp)) {
-                       RDEBUG2("&control.%s += \"%pV\"", group_ctx->inst->cache_da->name, &vp->data);
+                       RDEBUG2("&control.%s += \"%pV\"", group_ctx->inst->group.cache_da->name, &vp->data);
                }
        }
 
@@ -493,12 +492,12 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, request_t *req
        for (i = 0; (i < count); i++) {
                is_dn = fr_ldap_util_is_dn(values[i]->bv_val, values[i]->bv_len);
 
-               if (inst->cacheable_group_dn) {
+               if (inst->group.cacheable_dn) {
                        /*
                         *      The easy case, we're caching DNs and we got a DN.
                         */
                        if (is_dn) {
-                               MEM(vp = fr_pair_afrom_da(group_ctx->list_ctx, inst->cache_da));
+                               MEM(vp = fr_pair_afrom_da(group_ctx->list_ctx, inst->group.cache_da));
                                fr_pair_value_bstrndup(vp, values[i]->bv_val, values[i]->bv_len, true);
                                fr_pair_append(&group_ctx->groups, vp);
                        /*
@@ -517,12 +516,12 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, request_t *req
                        }
                }
 
-               if (inst->cacheable_group_name) {
+               if (inst->group.cacheable_name) {
                        /*
                         *      The easy case, we're caching names and we got a name.
                         */
                        if (!is_dn) {
-                               MEM(vp = fr_pair_afrom_da(group_ctx->list_ctx, inst->cache_da));
+                               MEM(vp = fr_pair_afrom_da(group_ctx->list_ctx, inst->group.cache_da));
                                fr_pair_value_bstrndup(vp, values[i]->bv_val, values[i]->bv_len, true);
                                fr_pair_append(&group_ctx->groups, vp);
                        /*
@@ -547,7 +546,7 @@ unlang_action_t rlm_ldap_cacheable_userobj(rlm_rcode_t *p_result, request_t *req
         *      do the resolution.
         */
        if ((name_p != group_ctx->group_name) || (dn_p != group_ctx->group_dn)) {
-               group_ctx->attrs[0] = inst->groupobj_name_attr;
+               group_ctx->attrs[0] = inst->group.obj_name_attr;
                if (unlang_function_push(request, ldap_cacheable_userobj_resolve, NULL, ldap_group_userobj_cancel,
                                         ~FR_SIGNAL_CANCEL, UNLANG_SUB_FRAME, group_ctx) < 0) {
                        talloc_free(group_ctx);
@@ -577,9 +576,9 @@ static unlang_action_t ldap_cacheable_groupobj_start(UNUSED rlm_rcode_t *p_resul
        ldap_group_groupobj_ctx_t       *group_ctx = talloc_get_type_abort(uctx, ldap_group_groupobj_ctx_t);
        rlm_ldap_t const                *inst = group_ctx->inst;
 
-       group_ctx->attrs[0] = inst->groupobj_name_attr;
+       group_ctx->attrs[0] = inst->group.obj_name_attr;
        return fr_ldap_trunk_search(group_ctx, &group_ctx->query, request, group_ctx->ttrunk,
-                                   group_ctx->base_dn->vb_strvalue, inst->groupobj_scope,
+                                   group_ctx->base_dn->vb_strvalue, inst->group.obj_scope,
                                    group_ctx->filter, group_ctx->attrs, NULL, NULL);
 }
 
@@ -643,7 +642,7 @@ static unlang_action_t ldap_cacheable_groupobj_resume(rlm_rcode_t *p_result, UNU
 
        RDEBUG2("Adding cacheable group object memberships");
        do {
-               if (inst->cacheable_group_dn) {
+               if (inst->group.cacheable_dn) {
                        dn = ldap_get_dn(query->ldap_conn->handle, entry);
                        if (!dn) {
                                ldap_get_option(query->ldap_conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
@@ -653,7 +652,7 @@ static unlang_action_t ldap_cacheable_groupobj_resume(rlm_rcode_t *p_result, UNU
                        }
                        fr_ldap_util_normalise_dn(dn, dn);
 
-                       MEM(pair_append_control(&vp, inst->cache_da) == 0);
+                       MEM(pair_append_control(&vp, inst->group.cache_da) == 0);
                        fr_pair_value_strdup(vp, dn, false);
 
                        RINDENT();
@@ -662,13 +661,13 @@ static unlang_action_t ldap_cacheable_groupobj_resume(rlm_rcode_t *p_result, UNU
                        ldap_memfree(dn);
                }
 
-               if (inst->cacheable_group_name) {
+               if (inst->group.cacheable_name) {
                        struct berval **values;
 
-                       values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->groupobj_name_attr);
+                       values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->group.obj_name_attr);
                        if (!values) continue;
 
-                       MEM(pair_append_control(&vp, inst->cache_da) == 0);
+                       MEM(pair_append_control(&vp, inst->group.cache_da) == 0);
                        fr_pair_value_bstrndup(vp, values[0]->bv_val, values[0]->bv_len, true);
 
                        RINDENT();
@@ -696,9 +695,9 @@ unlang_action_t rlm_ldap_cacheable_groupobj(rlm_rcode_t *p_result, request_t *re
 {
        rlm_ldap_t const                *inst = autz_ctx->inst;
        ldap_group_groupobj_ctx_t       *group_ctx;
-       char const                      *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
+       char const                      *filters[] = { inst->group.obj_filter, inst->group.obj_membership_filter };
 
-       if (!inst->groupobj_membership_filter) {
+       if (!inst->group.obj_membership_filter) {
                RDEBUG2("Skipping caching group objects as directive 'group.membership_filter' is not set");
                RETURN_MODULE_OK;
        }
@@ -796,7 +795,7 @@ unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, request_t
        };
 
        if (fr_ldap_util_is_dn(xlat_ctx->group->vb_strvalue, xlat_ctx->group->vb_length)) {
-               char const *filters[] = { inst->groupobj_filter, inst->groupobj_membership_filter };
+               char const *filters[] = { inst->group.obj_filter, inst->group.obj_membership_filter };
 
                RINDENT();
                ret = fr_ldap_xlat_filter(request,
@@ -813,9 +812,9 @@ unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, request_t
                group_ctx->base_dn = xlat_ctx->group;
        } else {
                char name_filter[LDAP_MAX_FILTER_STR_LEN];
-               char const *filters[] = { name_filter, inst->groupobj_filter, inst->groupobj_membership_filter };
+               char const *filters[] = { name_filter, inst->group.obj_filter, inst->group.obj_membership_filter };
 
-               if (!inst->groupobj_name_attr) {
+               if (!inst->group.obj_name_attr) {
                        REDEBUG("Told to search for group by name, but missing 'group.name_attribute' "
                                "directive");
 
@@ -823,7 +822,7 @@ unlang_action_t rlm_ldap_check_groupobj_dynamic(rlm_rcode_t *p_result, request_t
                }
 
                snprintf(name_filter, sizeof(name_filter), "(%s=%s)",
-                        inst->groupobj_name_attr, xlat_ctx->group->vb_strvalue);
+                        inst->group.obj_name_attr, xlat_ctx->group->vb_strvalue);
                RINDENT();
                ret = fr_ldap_xlat_filter(request,
                                          filters, NUM_ELEMENTS(filters),
@@ -851,7 +850,7 @@ static unlang_action_t ldap_dn2name_start (rlm_rcode_t *p_result, UNUSED int *pr
        ldap_memberof_xlat_ctx_t        *xlat_ctx = group_ctx->xlat_ctx;
        rlm_ldap_t const                *inst = xlat_ctx->inst;
 
-       if (!inst->groupobj_name_attr) {
+       if (!inst->group.obj_name_attr) {
                REDEBUG("Told to resolve group DN to name but missing 'group.name_attribute' directive");
                RETURN_MODULE_INVALID;
        }
@@ -918,7 +917,7 @@ static unlang_action_t ldap_check_userobj_resume(rlm_rcode_t *p_result, UNUSED i
                        RETURN_MODULE_FAIL;
                }
 
-               group_ctx->values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->userobj_membership_attr);
+               group_ctx->values = ldap_get_values_len(query->ldap_conn->handle, entry, inst->group.userobj_membership_attr);
                if (!group_ctx->values) {
                        RDEBUG2("No group membership attribute(s) found in user object");
                        RETURN_MODULE_FAIL;
@@ -960,9 +959,9 @@ static unlang_action_t ldap_check_userobj_resume(rlm_rcode_t *p_result, UNUSED i
                        RETURN_MODULE_INVALID;
                }
 
-               values = ldap_get_values_len(group_ctx->query->ldap_conn->handle, entry, inst->groupobj_name_attr);
+               values = ldap_get_values_len(group_ctx->query->ldap_conn->handle, entry, inst->group.obj_name_attr);
                if (!values) {
-                       REDEBUG("No %s attributes found in object", inst->groupobj_name_attr);
+                       REDEBUG("No %s attributes found in object", inst->group.obj_name_attr);
                        RETURN_MODULE_INVALID;
                }
 
@@ -1006,7 +1005,7 @@ static unlang_action_t ldap_check_userobj_resume(rlm_rcode_t *p_result, UNUSED i
 
                value_is_dn = fr_ldap_util_is_dn(value->bv_val, value->bv_len);
 
-               RDEBUG2("Processing %s value \"%pV\" as a %s", inst->userobj_membership_attr,
+               RDEBUG2("Processing %s value \"%pV\" as a %s", inst->group.userobj_membership_attr,
                        fr_box_strvalue_len(value->bv_val, value->bv_len),
                        value_is_dn ? "DN" : "group name");
 
@@ -1115,10 +1114,10 @@ unlang_action_t rlm_ldap_check_userobj_dynamic(rlm_rcode_t *p_result, request_t
 
        *group_ctx = (ldap_group_userobj_dyn_ctx_t) {
                .xlat_ctx = xlat_ctx,
-               .attrs = { inst->groupobj_name_attr, NULL }
+               .attrs = { inst->group.obj_name_attr, NULL }
        };
 
-       RDEBUG2("Checking user object's %s attributes", inst->userobj_membership_attr);
+       RDEBUG2("Checking user object's %s attributes", inst->group.userobj_membership_attr);
 
        /*
         *      If a previous query was required to find the user DN, that will have
@@ -1153,7 +1152,7 @@ unlang_action_t rlm_ldap_check_cached(rlm_rcode_t *p_result,
         *      We return RLM_MODULE_INVALID here as an indication
         *      the caller should try a dynamic group lookup instead.
         */
-       vp =  fr_pair_dcursor_by_da_init(&cursor, &request->control_pairs, inst->cache_da);
+       vp =  fr_pair_dcursor_by_da_init(&cursor, &request->control_pairs, inst->group.cache_da);
        if (!vp) RETURN_MODULE_INVALID;
 
        for (vp = fr_dcursor_current(&cursor);
index 99e83529e22f00b1d694e5fd3d929a32233b3dda..5f5b433b92f2ab913623971604217d37378fcbed 100644 (file)
@@ -109,18 +109,19 @@ static conf_parser_t user_config[] = {
  *     Group configuration
  */
 static conf_parser_t group_config[] = {
-       { FR_CONF_OFFSET("filter", rlm_ldap_t, groupobj_filter) },
-       { FR_CONF_OFFSET("scope", rlm_ldap_t, groupobj_scope), .dflt = "sub",
+       { FR_CONF_OFFSET("filter", rlm_ldap_t, group.obj_filter) },
+       { FR_CONF_OFFSET("scope", rlm_ldap_t, group.obj_scope), .dflt = "sub",
          .func = cf_table_parse_int, .uctx = &(cf_table_parse_ctx_t){ .table = fr_ldap_scope, .len = &fr_ldap_scope_len }  },
 
-       { FR_CONF_OFFSET("name_attribute", rlm_ldap_t, groupobj_name_attr), .dflt = "cn" },
-       { FR_CONF_OFFSET("membership_attribute", rlm_ldap_t, userobj_membership_attr) },
-       { FR_CONF_OFFSET_FLAGS("membership_filter", CONF_FLAG_XLAT, rlm_ldap_t, groupobj_membership_filter) },
-       { FR_CONF_OFFSET("cacheable_name", rlm_ldap_t, cacheable_group_name), .dflt = "no" },
-       { FR_CONF_OFFSET("cacheable_dn", rlm_ldap_t, cacheable_group_dn), .dflt = "no" },
-       { FR_CONF_OFFSET("cache_attribute", rlm_ldap_t, cache_attribute) },
-       { FR_CONF_OFFSET("group_attribute", rlm_ldap_t, group_attribute) },
-       { FR_CONF_OFFSET("allow_dangling_group_ref", rlm_ldap_t, allow_dangling_group_refs), .dflt = "no" },
+       { FR_CONF_OFFSET("name_attribute", rlm_ldap_t, group.obj_name_attr), .dflt = "cn" },
+       { FR_CONF_OFFSET("membership_attribute", rlm_ldap_t, group.userobj_membership_attr) },
+       { FR_CONF_OFFSET_FLAGS("membership_filter", CONF_FLAG_XLAT, rlm_ldap_t, group.obj_membership_filter) },
+       { FR_CONF_OFFSET("cacheable_name", rlm_ldap_t, group.cacheable_name), .dflt = "no" },
+       { FR_CONF_OFFSET("cacheable_dn", rlm_ldap_t, group.cacheable_dn), .dflt = "no" },
+       { FR_CONF_OFFSET("cache_attribute", rlm_ldap_t, group.cache_attribute) },
+       { FR_CONF_OFFSET("group_attribute", rlm_ldap_t, group.attribute) },
+       { FR_CONF_OFFSET("allow_dangling_group_ref", rlm_ldap_t, group.allow_dangling_refs), .dflt = "no" },
+       { FR_CONF_OFFSET("skip_on_suspend", rlm_ldap_t, group.skip_on_suspend), .dflt = "yes"},
        CONF_PARSER_TERMINATOR
 };
 
@@ -805,7 +806,7 @@ static unlang_action_t ldap_memberof_xlat_results(rlm_rcode_t *p_result, UNUSED
                if (!xlat_ctx->dn) xlat_ctx->dn = rlm_find_user_dn_cached(request);
                if (!xlat_ctx->dn) RETURN_MODULE_FAIL;
 
-               if (inst->groupobj_membership_filter) {
+               if (inst->group.obj_membership_filter) {
                        REPEAT_LDAP_MEMBEROF_XLAT_RESULTS;
                        if (rlm_ldap_check_groupobj_dynamic(&rcode, request, xlat_ctx) == UNLANG_ACTION_PUSHED_CHILD) {
                                xlat_ctx->status = GROUP_XLAT_MEMB_FILTER;
@@ -820,7 +821,7 @@ static unlang_action_t ldap_memberof_xlat_results(rlm_rcode_t *p_result, UNUSED
                        goto finish;
                }
 
-               if (inst->userobj_membership_attr) {
+               if (inst->group.userobj_membership_attr) {
                        REPEAT_LDAP_MEMBEROF_XLAT_RESULTS;
                        if (rlm_ldap_check_userobj_dynamic(&rcode, request, xlat_ctx) == UNLANG_ACTION_PUSHED_CHILD) {
                                xlat_ctx->status = GROUP_XLAT_MEMB_ATTR;
@@ -899,7 +900,7 @@ static xlat_action_t ldap_memberof_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat
                fr_value_box_bstr_realloc(group_vb, NULL, group_vb, len);
        }
 
-       if ((group_is_dn && inst->cacheable_group_dn) || (!group_is_dn && inst->cacheable_group_name)) {
+       if ((group_is_dn && inst->group.cacheable_dn) || (!group_is_dn && inst->group.cacheable_name)) {
                rlm_rcode_t our_rcode;
 
                rlm_ldap_check_cached(&our_rcode, inst, request, group_vb);
@@ -928,7 +929,7 @@ static xlat_action_t ldap_memberof_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, xlat
                .inst = inst,
                .group = group_vb,
                .dn = rlm_find_user_dn_cached(request),
-               .attrs = { inst->userobj_membership_attr, NULL },
+               .attrs = { inst->group.userobj_membership_attr, NULL },
                .group_is_dn = group_is_dn,
                .env_data = env_data
        };
@@ -1524,7 +1525,10 @@ static unlang_action_t mod_authorize_resume(rlm_rcode_t *p_result, UNUSED int *p
                        autz_ctx->access_state = rlm_ldap_check_access(inst, request, autz_ctx->entry);
                        switch (autz_ctx->access_state) {
                        case LDAP_ACCESS_ALLOWED:
+                               break;
+
                        case LDAP_ACCESS_SUSPENDED:
+                               if (inst->group.skip_on_suspend) goto post_group;
                                break;
 
                        case LDAP_ACCESS_DISALLOWED:
@@ -1536,10 +1540,10 @@ static unlang_action_t mod_authorize_resume(rlm_rcode_t *p_result, UNUSED int *p
                /*
                 *      Check if we need to cache group memberships
                 */
-               if ((inst->cacheable_group_dn || inst->cacheable_group_name) && (inst->userobj_membership_attr)) {
+               if ((inst->group.cacheable_dn || inst->group.cacheable_name) && (inst->group.userobj_membership_attr)) {
                        REPEAT_MOD_AUTHORIZE_RESUME;
                        if (rlm_ldap_cacheable_userobj(&rcode, request, autz_ctx,
-                                                      inst->userobj_membership_attr) == UNLANG_ACTION_PUSHED_CHILD) {
+                                                      inst->group.userobj_membership_attr) == UNLANG_ACTION_PUSHED_CHILD) {
                                autz_ctx->status = LDAP_AUTZ_GROUP;
                                return UNLANG_ACTION_PUSHED_CHILD;
                        }
@@ -1548,7 +1552,7 @@ static unlang_action_t mod_authorize_resume(rlm_rcode_t *p_result, UNUSED int *p
                FALL_THROUGH;
 
        case LDAP_AUTZ_GROUP:
-               if (inst->cacheable_group_dn || inst->cacheable_group_name) {
+               if (inst->group.cacheable_dn || inst->group.cacheable_name) {
                        REPEAT_MOD_AUTHORIZE_RESUME;
                        if (rlm_ldap_cacheable_groupobj(&rcode, request, autz_ctx) == UNLANG_ACTION_PUSHED_CHILD) {
                                autz_ctx->status = LDAP_AUTZ_POST_GROUP;
@@ -1559,6 +1563,7 @@ static unlang_action_t mod_authorize_resume(rlm_rcode_t *p_result, UNUSED int *p
                FALL_THROUGH;
 
        case LDAP_AUTZ_POST_GROUP:
+       post_group:
 #ifdef WITH_EDIR
                /*
                 *      We already have a Password.Cleartext.  Skip edir.
@@ -1792,9 +1797,9 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                expanded->attrs[expanded->count++] = inst->userobj_access_attr;
        }
 
-       if (inst->userobj_membership_attr && (inst->cacheable_group_dn || inst->cacheable_group_name)) {
+       if (inst->group.userobj_membership_attr && (inst->group.cacheable_dn || inst->group.cacheable_name)) {
                CHECK_EXPANDED_SPACE(expanded);
-               expanded->attrs[expanded->count++] = inst->userobj_membership_attr;
+               expanded->attrs[expanded->count++] = inst->group.userobj_membership_attr;
        }
 
        if (inst->profile_attr) {
@@ -2258,8 +2263,8 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx)
 
        inst->handle_config.name = talloc_typed_asprintf(inst, "rlm_ldap (%s)", mctx->inst->name);
 
-       if (inst->group_attribute) {
-               group_attribute = inst->group_attribute;
+       if (inst->group.attribute) {
+               group_attribute = inst->group.attribute;
        } else if (cf_section_name2(conf)) {
                snprintf(buffer, sizeof(buffer), "%s-LDAP-Group", mctx->inst->name);
                group_attribute = buffer;
@@ -2267,12 +2272,12 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx)
                group_attribute = "LDAP-Group";
        }
 
-       inst->group_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), group_attribute);
+       inst->group.da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), group_attribute);
 
        /*
         *      If the group attribute was not in the dictionary, create it
         */
-       if (!inst->group_da) {
+       if (!inst->group.da) {
                fr_dict_attr_flags_t    flags;
 
                memset(&flags, 0, sizeof(flags));
@@ -2282,25 +2287,25 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx)
                        return -1;
 
                }
-               inst->group_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), group_attribute);
+               inst->group.da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), group_attribute);
        }
 
        /*
         *      Setup the cache attribute
         */
-       if (inst->cache_attribute) {
+       if (inst->group.cache_attribute) {
                fr_dict_attr_flags_t    flags;
 
                memset(&flags, 0, sizeof(flags));
                if (fr_dict_attr_add(fr_dict_unconst(dict_freeradius), fr_dict_root(dict_freeradius),
-                                    inst->cache_attribute, -1, FR_TYPE_STRING, &flags) < 0) {
+                                    inst->group.cache_attribute, -1, FR_TYPE_STRING, &flags) < 0) {
                        PERROR("Error creating cache attribute");
                        return -1;
 
                }
-               inst->cache_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), inst->cache_attribute);
+               inst->group.cache_da = fr_dict_attr_by_name(NULL, fr_dict_root(dict_freeradius), inst->group.cache_attribute);
        } else {
-               inst->cache_da = inst->group_da;        /* Default to the group_da */
+               inst->group.cache_da = inst->group.da;  /* Default to the group_da */
        }
 
        /*
@@ -2445,8 +2450,8 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
        /*
         *      Sanity checks for cacheable groups code.
         */
-       if (inst->cacheable_group_name && inst->groupobj_membership_filter) {
-               if (!inst->groupobj_name_attr) {
+       if (inst->group.cacheable_name && inst->group.obj_membership_filter) {
+               if (!inst->group.obj_name_attr) {
                        cf_log_err(conf, "Configuration item 'group.name_attribute' must be set if cacheable "
                                      "group names are enabled");
 
index da3f285bd40e8ff3a853af7e84d22c3b3547e556..f47a53e7787db881f9feec4cf266415c8384817a 100644 (file)
@@ -41,7 +41,6 @@ typedef struct {
 
        int             userobj_scope;                  //!< Search scope.
 
-       char const      *userobj_membership_attr;       //!< Attribute that describes groups the user is a member of.
        char const      *userobj_access_attr;           //!< Attribute to check to see if the user should be locked out.
        bool            access_positive;                //!< If true the presence of the attribute will allow access,
                                                        //!< else it will deny access.
@@ -59,37 +58,43 @@ typedef struct {
        /*
         *      Group object attributes and filters
         */
-       char const      *groupobj_filter;               //!< Filter to retrieve only group objects.
-       int             groupobj_scope;                 //!< Search scope.
+       struct {
+               char const      *userobj_membership_attr;       //!< Attribute that describes groups the user is a member of.
 
-       char const      *groupobj_name_attr;            //!< The name of the group.
-       char const      *groupobj_membership_filter;    //!< Filter to only retrieve groups which contain
-                                                       //!< the user as a member.
+               char const      *obj_filter;                    //!< Filter to retrieve only group objects.
+               int             obj_scope;                      //!< Search scope.
 
-       bool            cacheable_group_name;           //!< If true the server will determine complete set of group
-                                                       //!< memberships for the current user object, and perform any
-                                                       //!< resolution necessary to determine the names of those
-                                                       //!< groups, then right them to the control list (LDAP-Group).
+               char const      *obj_name_attr;                 //!< The name of the group.
+               char const      *obj_membership_filter;         //!< Filter to only retrieve groups which contain
+                                                               //!< the user as a member.
 
-       bool            cacheable_group_dn;             //!< If true the server will determine complete set of group
-                                                       //!< memberships for the current user object, and perform any
-                                                       //!< resolution necessary to determine the DNs of those groups,
-                                                       //!< then right them to the control list (LDAP-GroupDN).
+               bool            cacheable_name;                 //!< If true the server will determine complete set of group
+                                                               //!< memberships for the current user object, and perform any
+                                                               //!< resolution necessary to determine the names of those
+                                                               //!< groups, then right them to the control list (LDAP-Group).
 
-       char const      *cache_attribute;               //!< Sets the attribute we use when creating and retrieving
-                                                       //!< cached group memberships.
+               bool            cacheable_dn;                   //!< If true the server will determine complete set of group
+                                                               //!< memberships for the current user object, and perform any
+                                                               //!< resolution necessary to determine the DNs of those groups,
+                                                               //!< then right them to the control list (LDAP-GroupDN).
 
-       fr_dict_attr_t const    *cache_da;              //!< The DA associated with this specific instance of the
-                                                       //!< rlm_ldap module.
+               char const      *cache_attribute;               //!< Sets the attribute we use when creating and retrieving
+                                                               //!< cached group memberships.
 
-       char const      *group_attribute;               //!< Sets the attribute we use when comparing group
-                                                       //!< group memberships.
+               fr_dict_attr_t const    *cache_da;              //!< The DA associated with this specific instance of the
+                                                               //!< rlm_ldap module.
 
-       fr_dict_attr_t const    *group_da;              //!< The DA associated with this specific instance of the
-                                                       //!< rlm_ldap module.
+               char const      *attribute;                     //!< Sets the attribute we use when comparing group
+                                                               //!< group memberships.
 
-       bool            allow_dangling_group_refs;      //!< Don't error if we fail to resolve a group DN referenced
-                                                       ///< from a user object.
+               fr_dict_attr_t const    *da;                    //!< The DA associated with this specific instance of the
+                                                               //!< rlm_ldap module.
+
+               bool            allow_dangling_refs;            //!< Don't error if we fail to resolve a group DN referenced
+                                                               ///< from a user object.
+
+               bool            skip_on_suspend;                //!< Don't process groups if the user is suspended.
+       } group;
 
        /*
         *      Profiles
index 1f8cca7ee9c3f212bf1a6414413d872b195162a6..fc2c8cd851c8efd7985ff3e565118ebc7cb0ef03 100644 (file)
@@ -29,7 +29,6 @@ RCSID("$Id$")
 USES_APPLE_DEPRECATED_API
 
 #include <freeradius-devel/util/debug.h>
-#include <ctype.h>
 
 #define LOG_PREFIX mctx->inst->name