27 #include <freeradius-devel/rad_assert.h>
46 char **names,
char **out,
size_t outlen)
52 unsigned int name_cnt = 0;
53 unsigned int entry_cnt;
54 char const *attrs[] = { NULL };
56 LDAPMessage *result = NULL, *entry;
60 char const *base_dn = NULL;
73 REDEBUG(
"Told to convert group names to DNs but missing 'group.name_attribute' directive");
78 RDEBUG(
"Converting group name(s) to group DN(s)");
87 names[0] && names[1] ?
"(|" :
"");
90 filter = talloc_asprintf_append_buffer(filter,
"(%s=%s)", inst->
groupobj_name_attr, buffer);
94 filter = talloc_asprintf_append_buffer(filter,
"%s%s",
96 names[0] && names[1] ?
")" :
"");
98 if (
tmpl_expand(&base_dn, base_dn_buff,
sizeof(base_dn_buff), request,
100 REDEBUG(
"Failed creating base_dn");
106 filter, attrs, NULL, NULL);
112 RDEBUG(
"Tried to resolve group name(s) to DNs but got no results");
120 entry_cnt = ldap_count_entries((*pconn)->handle, result);
121 if (entry_cnt > name_cnt) {
122 REDEBUG(
"Number of DNs exceeds number of names, group and/or dn should be more restrictive");
128 if (entry_cnt > (outlen - 1)) {
129 REDEBUG(
"Number of DNs exceeds limit (%zu)", outlen - 1);
135 if (entry_cnt < name_cnt) {
136 RWDEBUG(
"Got partial mapping of group names (%i) to DNs (%i), membership information may be incomplete",
137 name_cnt, entry_cnt);
140 entry = ldap_first_entry((*pconn)->handle, result);
142 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
143 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
150 *dn = ldap_get_dn((*pconn)->handle, entry);
152 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
153 REDEBUG(
"Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
160 RDEBUG(
"Got group DN \"%s\"", *dn);
162 }
while((entry = ldap_next_entry((*pconn)->handle, entry)));
169 ldap_msgfree(result);
177 while(*dn) ldap_memfree(*dn++);
203 struct berval **values = NULL;
205 LDAPMessage *result = NULL, *entry;
210 REDEBUG(
"Told to resolve group DN to name but missing 'group.name_attribute' directive");
215 RDEBUG(
"Resolving group DN \"%s\" to group name", dn);
217 status =
rlm_ldap_search(&result, inst, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL);
223 REDEBUG(
"Group DN \"%s\" did not resolve to an object", dn);
230 entry = ldap_first_entry((*pconn)->handle, result);
232 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
233 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
249 RDEBUG(
"Group DN \"%s\" resolves to name \"%s\"", dn, *out);
252 if (result) ldap_msgfree(result);
253 if (values) ldap_value_free_len(values);
268 LDAPMessage *entry,
char const *attr)
272 struct berval **values;
275 char **name_p = group_name;
283 TALLOC_CTX *list_ctx, *value_ctx;
294 values = ldap_get_values_len((*pconn)->handle, entry, attr);
296 RDEBUG2(
"No cacheable group memberships found in user object");
300 count = ldap_count_values_len(values);
308 value_ctx = talloc_new(request);
358 ldap_value_free_len(values);
359 talloc_free(value_ctx);
376 ldap_value_free_len(values);
377 talloc_free(value_ctx);
383 RDEBUG(
"Adding cacheable user object memberships");
395 for (dn_p = group_dn; *dn_p; dn_p++) {
421 LDAPMessage *result = NULL;
438 RDEBUG2(
"Skipping caching group objects as directive 'group.membership_filter' is not set");
444 filters,
sizeof(filters) /
sizeof(*filters),
445 filter,
sizeof(filter)) < 0) {
449 if (
tmpl_expand(&base_dn, base_dn_buff,
sizeof(base_dn_buff), request,
451 REDEBUG(
"Failed creating base_dn");
463 RDEBUG2(
"No cacheable group memberships found in group objects");
469 entry = ldap_first_entry((*pconn)->handle, result);
471 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
472 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
477 RDEBUG(
"Adding cacheable group object memberships");
480 dn = ldap_get_dn((*pconn)->handle, entry);
482 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
483 REDEBUG(
"Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
499 struct berval **values;
502 if (!values)
continue;
509 (
int)values[0]->bv_len, values[0]->bv_val);
512 ldap_value_free_len(values);
514 }
while ((entry = ldap_next_entry((*pconn)->handle, entry)));
517 if (result) ldap_msgfree(result);
552 REDEBUG(
"Operator \"%s\" not allowed for LDAP group comparisons",
557 RDEBUG2(
"Checking for user in group objects");
564 filters,
sizeof(filters) /
sizeof(*filters),
565 filter,
sizeof(filter));
570 base_dn = check->vp_strvalue;
576 REDEBUG(
"Told to search for group by name, but missing 'group.name_attribute' "
585 filters,
sizeof(filters) /
sizeof(*filters),
586 filter,
sizeof(filter));
599 REDEBUG(
"Failed creating base_dn");
610 RDEBUG(
"User found in group object \"%s\"", base_dn);
637 bool name_is_dn =
false, value_is_dn =
false;
639 LDAPMessage *result = NULL;
640 LDAPMessage *entry = NULL;
641 struct berval **values = NULL;
644 int i, count, ldap_errno;
648 status =
rlm_ldap_search(&result, inst, request, pconn, dn, LDAP_SCOPE_BASE, NULL, attrs, NULL, NULL);
655 RDEBUG(
"Can't check membership attributes, user object not found");
664 entry = ldap_first_entry((*pconn)->handle, result);
666 ldap_get_option((*pconn)->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
667 REDEBUG(
"Failed retrieving entry: %s", ldap_err2string(ldap_errno));
676 RDEBUG(
"No group membership attribute(s) found in user object");
685 name_is_dn =
rlm_ldap_is_dn(check->vp_strvalue, check->vp_length);
686 count = ldap_count_values_len(values);
687 for (i = 0; i < count; i++) {
688 value_is_dn =
rlm_ldap_is_dn(values[i]->bv_val, values[i]->bv_len);
691 (
int)values[i]->bv_len, values[i]->bv_val, value_is_dn ?
"DN" :
"group name");
696 if (!name_is_dn && !value_is_dn) {
697 if ((check->vp_length == values[i]->bv_len) &&
698 (memcmp(values[i]->bv_val, check->vp_strvalue, values[i]->bv_len) == 0)) {
699 RDEBUG(
"User found in group \"%s\". Comparison between membership: name, check: name",
712 if (name_is_dn && value_is_dn) {
713 if (check->vp_length == values[i]->bv_len) {
716 for (j = 0; j < (int)values[i]->bv_len; j++) {
717 if (tolower(values[i]->bv_val[j]) != tolower(check->vp_strvalue[j]))
break;
719 if (j == (
int)values[i]->bv_len) {
720 RDEBUG(
"User found in group DN \"%s\". "
721 "Comparison between membership: dn, check: dn", check->vp_strvalue);
735 if (!value_is_dn && name_is_dn) {
747 if (((talloc_array_length(resolved) - 1) == values[i]->bv_len) &&
748 (memcmp(values[i]->bv_val, resolved, values[i]->bv_len) == 0)) eq =
true;
749 talloc_free(resolved);
751 RDEBUG(
"User found in group \"%.*s\". Comparison between membership: name, check: name "
752 "(resolved from DN \"%s\")", (
int)values[i]->bv_len,
753 values[i]->bv_val, check->vp_strvalue);
766 if (value_is_dn && !name_is_dn) {
781 if (((talloc_array_length(resolved) - 1) == check->vp_length) &&
782 (memcmp(check->vp_strvalue, resolved, check->vp_length) == 0)) eq =
true;
783 talloc_free(resolved);
785 RDEBUG(
"User found in group \"%s\". Comparison between membership: name "
786 "(resolved from DN \"%s\"), check: name", check->vp_strvalue, value);
798 if (values) ldap_value_free_len(values);
799 if (result) ldap_msgfree(result);
831 RDEBUG2(
"User found. Matched cached membership");
840 RDEBUG2(
"Cached membership not found");
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
ssize_t tmpl_expand(char const **out, char *buff, size_t outlen, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a vp_tmpl_t to a string writing the result to a buffer.
Tracks the state of a libldap connection handle.
VALUE_PAIR * fr_cursor_first(vp_cursor_t *cursor)
Rewind cursor to the start of the list.
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Operation was successfull.
#define RINDENT()
Indent R* messages by one level.
#define LDAP_MAX_GROUP_NAME_LEN
Maximum name of a group name.
The module is OK, continue.
VALUE_PAIR * fr_cursor_next_by_num(vp_cursor_t *cursor, unsigned int vendor, unsigned int attr, int8_t tag)
Iterate over a collection of VALUE_PAIRs of a given type in the pairlist.
static rlm_rcode_t rlm_ldap_group_name2dn(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char **names, char **out, size_t outlen)
Convert multiple group names into a DNs.
vp_tmpl_t * groupobj_base_dn
DN to search for users under.
TALLOC_CTX * radius_list_ctx(REQUEST *request, pair_lists_t list_name)
Return the correct TALLOC_CTX to alloc VALUE_PAIR in, for a list.
VALUE_PAIR ** radius_list(REQUEST *request, pair_lists_t list)
Resolve attribute pair_lists_t value to an attribute list.
int groupobj_scope
Search scope.
#define RDEBUG_ENABLED
True if request debug level 1 messages are enabled.
const FR_NAME_NUMBER fr_tokens_table[]
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
bool cacheable_group_name
If true the server will determine complete set of group memberships for the current user object...
The module considers the request invalid.
bool cacheable_group_dn
If true the server will determine complete set of group memberships for the current user object...
ldap_rcode_t
Codes returned by rlm_ldap internal functions.
#define LDAP_MAX_FILTER_STR_LEN
Maximum length of an xlat expanded filter.
char const * groupobj_filter
Filter to retrieve only group objects.
size_t rlm_ldap_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
rlm_rcode_t rlm_ldap_check_userobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, VALUE_PAIR *check)
Query the LDAP directory to check if a user object is a member of a group.
char const * userobj_membership_attr
Attribute that describes groups the user is a member of.
rlm_rcode_t rlm_ldap_cacheable_userobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, LDAPMessage *entry, char const *attr)
Convert group membership information into attributes.
#define LDAP_MAX_DN_STR_LEN
Maximum length of an xlat expanded DN.
char const * groupobj_name_attr
The name of the group.
void fr_pair_value_strcpy(VALUE_PAIR *vp, char const *src)
Copy data into an "string" data type.
void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *vp)
Merges multiple VALUE_PAIR into the cursor.
fr_dict_attr_t const * cache_da
The DA associated with this specific instance of the.
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
#define pair_make_config(_a, _b, _c)
unsigned int attr
Attribute number.
unsigned int vendor
Vendor that defines this attribute.
#define fr_pair_cmp_op(_op, _a, _b)
Compare two attributes using and operator.
char const * groupobj_membership_filter
Filter to only retrieve groups which contain the user as a member.
Stores an attribute, a value and various bits of other data.
ssize_t rlm_ldap_xlat_filter(REQUEST *request, char const **sub, size_t sublen, char *out, size_t outlen)
Combine and expand filters.
char * talloc_typed_asprintf(void const *t, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
ldap_rcode_t rlm_ldap_search(LDAPMessage **result, rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, int scope, char const *filter, char const *const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls)
Search for something in the LDAP directory.
#define REXDENT()
Exdent (unindent) R* messages by one level.
FR_TOKEN op
Operator to use when moving or inserting valuepair into a list.
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
rlm_rcode_t rlm_ldap_cacheable_groupobj(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn)
Convert group membership information into attributes.
char name[1]
Attribute name.
Module failed, don't reply.
rlm_rcode_t rlm_ldap_check_cached(rlm_ldap_t const *inst, REQUEST *request, VALUE_PAIR *check)
Check group membership attributes to see if a user is a member.
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
static rlm_rcode_t rlm_ldap_group_dn2name(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, char **out)
Convert a single group name into a DN.
size_t rlm_ldap_escape_func(UNUSED REQUEST *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Converts "bad" strings into ones which are safe for LDAP.
VALUE_PAIR * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute.
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
char * rlm_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
#define LDAP_MAX_CACHEABLE
Maximum number of groups we retrieve from the server for.
void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
Copy data into an "string" data type.
Attributes that change the behaviour of modules.
rlm_rcode_t rlm_ldap_check_groupobj_dynamic(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, VALUE_PAIR *check)
Query the LDAP directory to check if a group object includes a user object as a member.
LDAP authorization and authentication module headers.
bool rlm_ldap_is_dn(char const *in, size_t inlen)
Check whether a string looks like a DN.