26RCSID(
"$Id: 500e25662db2c71ce84cc885ba81aa5a854479f4 $")
30#include <freeradius-devel/ldap/base.h>
31#include <freeradius-devel/util/base16.h>
33#include <freeradius-devel/util/value.h>
39static const char hextab[] =
"0123456789abcdef";
199 size_t freespace = outlen;
201 if (outlen <= 1)
return 0;
204 while (*p && (--freespace > 0)) {
220 if (!(c1 = memchr(
hextab, tolower(p[0]), 16)) ||
221 !(c2 = memchr(
hextab, tolower(p[1]), 16)))
goto next;
230 return outlen - freespace;
247 bool too_soon =
true;
259 if (
inlen < 2)
return false;
282 if (
inlen < 3)
return false;
301 if (too_soon || (*p != want))
return false;
307 if (too_soon || (*p != want))
return false;
325 if (too_soon || (
comp < 2))
return false;
342 LDAPControl **sss_p = sss, **sss_end = sss_p + sss_len;
353 for (i = 0; extensions[i]; i++) {
355 bool is_critical =
false;
357 if (sss_p == sss_end) {
374 "in the format \"[!]sss=<key>[,key]\"");
378 if (*s) ldap_control_free(*s);
385 if (ret != LDAP_SUCCESS) {
391 if (*sss_p) ldap_control_free(*sss_p);
394 ldap_free_sort_keylist(keys);
395 if (ret != LDAP_SUCCESS) {
397 ldap_err2string(ret));
408 struct berval attr_value;
414 "in the format \"[!]vlv=<before>/<after>(/<offset>/<count>|:<value>)");
418 vlvinfo.ldvlv_context = NULL;
420 if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0)
goto vlv_error;
422 vlvinfo.ldvlv_before_count = ext_value;
424 if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0)
goto vlv_error;
425 vlvinfo.ldvlv_after_count = ext_value;
430 vlvinfo.ldvlv_attrvalue = NULL;
432 if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0)
goto vlv_error;
434 vlvinfo.ldvlv_offset = ext_value;
436 if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0)
goto vlv_error;
437 vlvinfo.ldvlv_count = ext_value;
443 vlvinfo.ldvlv_attrvalue = &attr_value;
449 if (ret != LDAP_SUCCESS) {
451 ldap_err2string(ret));
464 return (sss_end - sss_p);
476 ber_free(iter->
ber, 0);
492 if (iter->
end)
return NULL;
494 if (ber_scanf(iter->
ber,
"m", &iter->
value) == LBER_ERROR) {
501 if (ber_next_element(iter->
ber, &iter->
len, iter->
last) == LBER_DEFAULT) iter->
end =
true;
526 struct berval dn,
name;
527 size_t attr_len = strlen(
attr);
532 if (ldap_get_dn_ber(handle, entry, &iter->
ber, &dn) != LDAP_SUCCESS) {
541 if (ber_get_option(iter->
ber, LBER_OPT_BER_REMAINING_BYTES, &remaining) != LBER_OPT_SUCCESS)
goto error;
542 if (remaining == 0)
break;
544 if (ber_scanf(iter->
ber,
"{m" , &
name) == LBER_ERROR)
goto error;
547 if (ber_scanf(iter->
ber,
"x") == LBER_ERROR)
goto error;
551 if (ber_first_element(iter->
ber, &iter->
len, &iter->
last) != LBER_DEFAULT) iter->
found =
true;
591 LDAP *handle, LDAPMessage *entry,
char const *
attr)
594 struct berval *
value;
627 for (entry = ldap_first_entry(handle, result); entry; entry = ldap_next_entry(handle, entry)) {
629 struct berval *
value;
635 *strings_len +=
value->bv_len + 1;
664 char const *
attr,
size_t extra)
668 size_t num = 0, strings_len = 0;
677 if (num == 0)
return list;
679 for (entry = ldap_first_entry(handle, result); entry; entry = ldap_next_entry(handle, entry)) {
681 struct berval *
value;
718 struct berval *
value;
719 int num = 0,
err = 0;
749 out = talloc_array(ctx,
char,
in->bv_len + 1);
750 if (!
out)
return NULL;
752 memcpy(
out,
in->bv_val,
in->bv_len);
753 out[
in->bv_len] =
'\0';
769 if (!
out)
return NULL;
771 memcpy(
out,
in->bv_val,
in->bv_len);
799 for (p =
in; *p !=
'\0'; p++) {
846 size_t f_len, p_len, i;
848 if (!full)
return -1;
850 f_len = strlen(full);
852 if (!part)
return -1;
854 p_len = strlen(part);
855 if (!p_len)
return f_len;
857 if ((f_len < p_len) || !f_len)
return -1;
859 for (i = 0; i < p_len; i++)
if (part[p_len - 1 - i] != full[f_len - 1 - i])
return -1;
861 return f_len - p_len;
877 char const *
const *dn_list)
881 char const *
const *dn_p;
882 bool has_filter = filter && *filter;
884 MEM(fr_sbuff_init_talloc(ctx, &sbuff, &sbuff_ctx, 256, SIZE_MAX));
888 for (dn_p = dn_list; *dn_p; dn_p++) {
913 char const *
in = NULL;
924 for (i = 0; i < sublen; i++) {
925 if (sub[i] && *sub[i]) {
928 len += strlen(sub[i]);
938 buffer = talloc_array(ctx,
char, len + 4);
941 for (i = 0; i < sublen; i++) {
942 if (sub[i] && (*sub[i] !=
'\0')) {
976 if (!
attr)
return -1;
978 len = talloc_array_length(attrs);
980 for (i = 0; i < len; i++) {
981 if (!attrs[i])
continue;
1000 LDAPURLDesc *ldap_url;
1001 bool set_port_maybe =
true;
1002 int default_port = LDAP_PORT;
1007 if (ldap_url_parse(server, &ldap_url)) {
1008 cf_log_err(ci,
"Parsing LDAP URL \"%s\" failed", server);
1010 ldap_free_urldesc(ldap_url);
1014 if (ldap_url->lud_dn && (ldap_url->lud_dn[0] !=
'\0')) {
1015 cf_log_err(ci,
"Base DN cannot be specified via server URL");
1016 goto ldap_url_error;
1019 if (ldap_url->lud_attrs && ldap_url->lud_attrs[0]) {
1020 cf_log_err(ci,
"Attribute list cannot be speciried via server URL");
1021 goto ldap_url_error;
1027 if (ldap_url->lud_scope != LDAP_SCOPE_BASE) {
1028 cf_log_err(ci,
"Scope cannot be specified via server URL");
1029 goto ldap_url_error;
1031 ldap_url->lud_scope = -1;
1038 if ((p = strchr(server,
']')) && (p[1] ==
':')) {
1039 set_port_maybe =
false;
1040 }
else if ((p = strchr(server,
':')) && (strchr(p+1,
':') != NULL)) {
1041 set_port_maybe =
false;
1047 if (ldap_url->lud_scheme) {
1048 if (strcmp(ldap_url->lud_scheme,
"ldaps") == 0) {
1050 cf_log_err(ci,
"ldaps:// scheme is not compatible with 'start_tls'");
1051 goto ldap_url_error;
1053 default_port = LDAPS_PORT;
1054 handle_config->
tls_mode = LDAP_OPT_X_TLS_HARD;
1055 }
else if (strcmp(ldap_url->lud_scheme,
"ldapi") == 0) {
1056 set_port_maybe =
false;
1060 if (set_port_maybe) {
1064 ldap_url->lud_port = handle_config->
port;
1071 if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
1074 url = ldap_url_desc2str(ldap_url);
1076 cf_log_err(ci,
"Failed recombining URL components");
1077 goto ldap_url_error;
1079 handle_config->
server = talloc_asprintf_append(handle_config->
server,
"%s ",
url);
1081 ldap_free_urldesc(ldap_url);
1102 port = handle_config->
port;
1108 if (strchr(server,
'/')) {
1112 cf_log_err(ci,
"Invalid 'server' entry, must be in format <server>[:<port>] or "
1113 "an ldap URI (ldap|cldap|ldaps|ldapi)://<server>:<port>");
1117 p = strrchr(server,
':');
1119 port = (int)strtol((p + 1), &q, 10);
1120 if ((p == server) || ((p + 1) == q) || (*q !=
'\0'))
goto bad_server_fmt;
1123 len = strlen(server);
1125 if (port == 0) port = LDAP_PORT;
1127 handle_config->
server = talloc_asprintf_append(handle_config->
server,
"ldap://%.*s:%i ",
1128 (
int)len, server, port);
1138 switch (ldap_url_err) {
1139 case LDAP_URL_SUCCESS:
1142 case LDAP_URL_ERR_MEM:
1145 case LDAP_URL_ERR_PARAM:
1146 return "parameter is bad";
1148 case LDAP_URL_ERR_BADSCHEME:
1149 return "URL doesn't begin with \"[c]ldap[si]://\"";
1151 case LDAP_URL_ERR_BADENCLOSURE:
1152 return "URL is missing trailing \">\"";
1154 case LDAP_URL_ERR_BADURL:
1155 return "URL is bad";
1157 case LDAP_URL_ERR_BADHOST:
1158 return "host/port is bad";
1160 case LDAP_URL_ERR_BADATTRS:
1161 return "bad (or missing) attributes";
1163 case LDAP_URL_ERR_BADSCOPE:
1164 return "scope string is invalid (or missing)";
1166 case LDAP_URL_ERR_BADFILTER:
1167 return "bad or missing filter";
1169 case LDAP_URL_ERR_BADEXTS:
1170 return "bad or missing extensions";
1173 return "unknown reason";
1186 BerElement *ber = NULL;
1188 struct berval **vals;
1193 msgtype = ldap_msgtype(entry);
1195 case LDAP_RES_SEARCH_ENTRY:
1196 dn = ldap_get_dn(ld, entry);
1198 DEBUG(
"dn: %s", dn);
1202 for (
attr = ldap_first_attribute(ld, entry, &ber);
1204 attr = ldap_next_attribute(ld, entry, ber)) {
1205 vals = ldap_get_values_len(ld, entry,
attr);
1212 for (i = 0; vals[i] != NULL; i++) {
1213 bool binary =
false;
1216 for (j = 0; j < vals[i]->bv_len; j++) {
1217 char c = vals[i]->bv_val[j];
1218 if ((c < 32) || (c > 126)) {
1232 ldap_value_free_len(vals);
1237 case LDAP_RES_SEARCH_RESULT:
1239 case LDAP_RES_MODIFY:
1241 case LDAP_RES_DELETE:
1242 case LDAP_RES_COMPARE:
1243 case LDAP_RES_EXTENDED:
1246 char *matched = NULL;
1247 char *errmsg = NULL;
1250 rc = ldap_parse_result(ld, entry, &msgtype, &matched, &errmsg, &refs, NULL, 0);
1251 if (rc != LDAP_SUCCESS) {
1252 DEBUG(
"failed to parse result: %s", ldap_err2string(rc));
1256 DEBUG(
"result code: %d (%s)", msgtype, ldap_err2string(msgtype));
1258 if (matched && *matched) {
1259 DEBUG(
"matched DN: %s", matched);
1261 if (errmsg && *errmsg) {
1262 DEBUG(
"error message: %s", errmsg);
1265 for (i = 0; refs[i] != NULL; i++) {
1266 DEBUG(
"referral: %s", refs[i]);
1270 if (matched) ldap_memfree(matched);
1271 if (errmsg) ldap_memfree(errmsg);
1272 if (refs) ldap_memvfree((
void **)refs);
1277 DEBUG(
"unhandled LDAP message type: %d", msgtype);
1281 if (ber) ber_free(ber, 0);
static int const char char buffer[256]
strcpy(log_entry->msg, buffer)
#define fr_base16_decode(_err, _out, _in, _no_trailing)
#define fr_base16_encode_byte(_out, _byte)
#define USES_APPLE_DEPRECATED_API
Common header for all CONF_* types.
A section grouping multiple CONF_PAIR.
CONF_PAIR * cf_pair_find(CONF_SECTION const *cs, char const *attr)
Search for a CONF_PAIR with a specific name.
#define cf_log_err(_cf, _fmt,...)
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static char const escape_chars[]
ber_len_t len
Length of the current element.
#define LDAP_DN_SAFE_FOR
Marks a value box as already escaped for use as a DN attribute value.
char * last
End marker of the value set.
char * server
Initial server to bind to.
#define LDAP_FILTER_SAFE_FOR
Marks a value box as already escaped for use as a filter assertion value.
bool end
All values have been returned.
bool start_tls
Send the Start TLS message to the LDAP directory to start encrypted communications using the standard...
bool found
The attribute was found in the entry.
BerElement * ber
Cursor over the entry.
uint16_t port
Port to use when binding to the server.
struct berval value
Value the iterator is positioned on.
Connection configuration.
State of an in place iteration over an attribute's values.
LDAP * fr_ldap_handle_thread_local(void)
Get a thread local dummy LDAP handle.
char const * fr_ldap_url_err_to_str(int ldap_url_err)
Translate the error code emitted from ldap_url_parse and friends into something accessible with fr_st...
struct berval * fr_ldap_value_iter_init(int *err, fr_ldap_value_iter_t *iter, LDAP *handle, LDAPMessage *entry, char const *attr)
Start an in place iteration over an attribute's values in an entry.
static const char hextab[]
static int _fr_ldap_value_iter_free(fr_ldap_value_iter_t *iter)
Free the ber held by an allocated value iterator.
size_t fr_ldap_util_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
static const bool escapes[SBUFF_CHAR_CLASS]
int fr_ldap_entry_value_find(struct berval *out, LDAP *handle, LDAPMessage *entry, char const *attr)
Find an attribute in an entry, returning its first value referenced in place.
int fr_ldap_filter_box_escape(fr_value_box_t *vb, UNUSED void *uctx)
Escape a value box for use as an RFC 4515 filter assertion value.
void fr_ldap_value_iter_done(fr_ldap_value_iter_t *iter)
Release value iteration state.
bool fr_ldap_util_is_dn(char const *in, size_t inlen)
Check whether a string looks like a DN.
fr_slen_t fr_ldap_dn_escape(fr_sbuff_t *out, fr_sbuff_t *in)
Escape a value for use as an RFC 4514 DN attribute value.
size_t fr_ldap_common_dn(char const *full, char const *part)
Find the place at which the two DN strings diverge.
struct berval * fr_ldap_value_iter_next(int *err, fr_ldap_value_iter_t *iter)
Return the next value of the iterated attribute.
int fr_ldap_attrs_check(char const **attrs, char const *attr)
Check that a particular attribute is included in an attribute list.
uint8_t * fr_ldap_berval_to_bin(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced buffer.
int fr_ldap_result_values_len(size_t *num, size_t *strings_len, LDAP *handle, LDAPMessage *result, char const *attr)
Sum the lengths of an attribute's values across every entry of a result.
int fr_ldap_server_url_check(fr_ldap_config_t *handle_config, char const *server, CONF_SECTION const *cs)
Check an LDAP server entry in URL format is valid.
static USES_APPLE_DEPRECATED_API const char dn_specials[]
fr_slen_t fr_ldap_filter_escape(fr_sbuff_t *out, fr_sbuff_t *in)
Escape a value for use as an RFC 4515 filter assertion value.
char * fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
static fr_slen_t ldap_escape(fr_sbuff_t *out, fr_sbuff_t *in, bool const *escape_chars)
Copy in to out, hex escaping every byte flagged in escape_chars.
int fr_ldap_server_config_check(fr_ldap_config_t *handle_config, char const *server, CONF_SECTION *cs)
Check an LDAP server config in server:port format is valid.
talloc_str_list_t * fr_ldap_str_list_afrom_result(TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *result, char const *attr, size_t extra)
Copy an attribute's values from every entry of a result into a string list.
int fr_ldap_dn_box_escape(fr_value_box_t *vb, UNUSED void *uctx)
Escape a value box for use as an RFC 4514 DN attribute value.
size_t fr_ldap_uri_unescape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Converts escaped DNs and filter strings into normal.
void fr_ldap_entry_dump(LDAPMessage *entry)
Dump out the contents of an LDAPMessage.
int fr_ldap_parse_url_extensions(LDAPControl **sss, size_t sss_len, char *extensions[])
Parse a subset (just server side sort and virtual list view for now) of LDAP URL extensions.
int fr_ldap_filter_to_tmpl(TALLOC_CTX *ctx, tmpl_rules_t const *t_rules, char const **sub, size_t sublen, tmpl_t **out)
Combine filters and tokenize to a tmpl.
struct berval * fr_ldap_value_iter_alloc(int *err, fr_ldap_value_iter_t **out, TALLOC_CTX *ctx, LDAP *handle, LDAPMessage *entry, char const *attr)
Allocate a value iterator, released when the iterator is freed.
char * fr_ldap_filter_afrom_dn_list(TALLOC_CTX *ctx, char const *dn_attr, char const *filter, char const *const *dn_list)
Build a filter matching a set of objects by DN.
#define EMARKER(_str, _marker_idx, _marker)
int strncasecmp(char *s1, char *s2, int n)
int strcasecmp(char *s1, char *s2)
static char const * url[FR_RADIUS_FAIL_MAX+1]
static fr_cmp_ret_t comp(void const *a, void const *b)
int fr_sbuff_trim_talloc(fr_sbuff_t *sbuff, size_t len)
Trim a talloced sbuff to the minimum length required to represent the contained string.
size_t fr_sbuff_adv_past_str(fr_sbuff_t *sbuff, char const *needle, size_t needle_len)
Return true and advance past the end of the needle if needle occurs next in the sbuff.
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define FR_SBUFF_IN(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_buff(_sbuff_or_marker)
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define FR_SBUFF_IN_STR(_start)
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define fr_sbuff_out(_err, _out, _in)
#define fr_sbuff_remaining(_sbuff_or_marker)
#define fr_sbuff_in_strcpy_literal(_sbuff, _str)
#define fr_sbuff_in_char(_sbuff,...)
Talloc sbuff extension structure.
ssize_t tmpl_afrom_substr(TALLOC_CTX *ctx, tmpl_t **out, fr_sbuff_t *in, fr_token_t quote, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Convert an arbitrary string into a tmpl_t.
Optional arguments passed to vp_tmpl functions.
talloc_str_list_t * talloc_str_list_alloc(TALLOC_CTX *ctx, size_t num, size_t strings_len)
Allocate a list to hold num strings of strings_len total length.
char const * talloc_str_list_append(talloc_str_list_t *list, char const *str, size_t len)
Append a copy of a string to a string list.
char const ** p
Where the next appended string is written.
A NULL terminated array of strings with an append cursor.
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
int fr_value_box_escape_in_place_func(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_sbuff_escape_func_t escape)
Escape a value box in place using an sbuff escape function.
#define fr_value_box_is_safe_for_only(_box, _safe_for)
#define fr_box_strvalue_len(_val, _len)
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out
#define fr_box_octets(_val, _len)