# `(<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'
}
#
USES_APPLE_DEPRECATED_API
#include <freeradius-devel/util/debug.h>
-#include <ctype.h>
#define LOG_PREFIX "rlm_ldap groups"
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;
}
* 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);
}
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);
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;
}
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:
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);
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);
}
}
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);
/*
}
}
- 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);
/*
* 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);
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);
}
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);
}
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();
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();
{
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;
}
};
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,
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");
}
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),
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;
}
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;
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;
}
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");
*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
* 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);
* 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
};
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;
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;
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);
.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
};
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:
/*
* 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;
}
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;
FALL_THROUGH;
case LDAP_AUTZ_POST_GROUP:
+ post_group:
#ifdef WITH_EDIR
/*
* We already have a Password.Cleartext. Skip edir.
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) {
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;
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));
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 */
}
/*
/*
* 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");
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.
/*
* 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
USES_APPLE_DEPRECATED_API
#include <freeradius-devel/util/debug.h>
-#include <ctype.h>
#define LOG_PREFIX mctx->inst->name