26RCSID(
"$Id: 8af3eee0cb170260d3d86aaf26cd31c273896411 $")
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";
106 return outlen - left;
121 if (!fr_sbuff_init_talloc(vb, &sbuff, &sbuff_ctx, vb->vb_length * 3, vb->vb_length * 3)) {
131 if (len == vb->vb_length) {
157 size_t left = outlen;
161 if (left <= 3)
break;
172 if (left <= 1)
break;
180 return outlen - left;
195 if (!fr_sbuff_init_talloc(vb, &sbuff, &sbuff_ctx, vb->vb_length * 3, vb->vb_length * 3)) {
202 if (len == vb->vb_length) {
232 size_t freespace = outlen;
234 if (outlen <= 1)
return 0;
237 while (*p && (--freespace > 0)) {
253 if (!(c1 = memchr(
hextab, tolower(p[0]), 16)) ||
254 !(c2 = memchr(
hextab, tolower(p[1]), 16)))
goto next;
263 return outlen - freespace;
280 bool too_soon =
true;
292 if (
inlen < 2)
return false;
315 if (
inlen < 3)
return false;
334 if (too_soon || (*p != want))
return false;
340 if (too_soon || (*p != want))
return false;
358 if (too_soon || (
comp < 2))
return false;
375 LDAPControl **sss_p = sss, **sss_end = sss_p + sss_len;
386 for (i = 0; extensions[i]; i++) {
388 bool is_critical =
false;
390 if (sss_p == sss_end) {
407 "in the format \"[!]sss=<key>[,key]\"");
411 if (*s) ldap_control_free(*s);
418 if (ret != LDAP_SUCCESS) {
424 if (*sss_p) ldap_control_free(*sss_p);
427 ldap_free_sort_keylist(keys);
428 if (ret != LDAP_SUCCESS) {
430 ldap_err2string(ret));
441 struct berval attr_value;
447 "in the format \"[!]vlv=<before>/<after>(/<offset>/<count>|:<value>)");
451 vlvinfo.ldvlv_context = NULL;
453 if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0)
goto vlv_error;
455 vlvinfo.ldvlv_before_count = ext_value;
457 if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0)
goto vlv_error;
458 vlvinfo.ldvlv_after_count = ext_value;
463 vlvinfo.ldvlv_attrvalue = NULL;
465 if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0)
goto vlv_error;
467 vlvinfo.ldvlv_offset = ext_value;
469 if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0)
goto vlv_error;
470 vlvinfo.ldvlv_count = ext_value;
476 vlvinfo.ldvlv_attrvalue = &attr_value;
482 if (ret != LDAP_SUCCESS) {
484 ldap_err2string(ret));
497 return (sss_end - sss_p);
509 ber_free(iter->
ber, 0);
525 if (iter->
end)
return NULL;
527 if (ber_scanf(iter->
ber,
"m", &iter->
value) == LBER_ERROR) {
534 if (ber_next_element(iter->
ber, &iter->
len, iter->
last) == LBER_DEFAULT) iter->
end =
true;
559 struct berval dn,
name;
560 size_t attr_len = strlen(attr);
565 if (ldap_get_dn_ber(handle, entry, &iter->
ber, &dn) != LDAP_SUCCESS) {
574 if (ber_get_option(iter->
ber, LBER_OPT_BER_REMAINING_BYTES, &remaining) != LBER_OPT_SUCCESS)
goto error;
575 if (remaining == 0)
break;
577 if (ber_scanf(iter->
ber,
"{m" , &
name) == LBER_ERROR)
goto error;
580 if (ber_scanf(iter->
ber,
"x") == LBER_ERROR)
goto error;
584 if (ber_first_element(iter->
ber, &iter->
len, &iter->
last) != LBER_DEFAULT) iter->
found =
true;
624 LDAP *handle, LDAPMessage *entry,
char const *attr)
627 struct berval *
value;
660 for (entry = ldap_first_entry(handle, result); entry; entry = ldap_next_entry(handle, entry)) {
662 struct berval *
value;
668 *strings_len +=
value->bv_len + 1;
697 char const *attr,
size_t extra)
701 size_t num = 0, strings_len = 0;
710 if (num == 0)
return list;
712 for (entry = ldap_first_entry(handle, result); entry; entry = ldap_next_entry(handle, entry)) {
714 struct berval *
value;
751 struct berval *
value;
752 int num = 0,
err = 0;
782 out = talloc_array(ctx,
char,
in->bv_len + 1);
783 if (!
out)
return NULL;
785 memcpy(
out,
in->bv_val,
in->bv_len);
786 out[
in->bv_len] =
'\0';
802 if (!
out)
return NULL;
804 memcpy(
out,
in->bv_val,
in->bv_len);
832 for (p =
in; *p !=
'\0'; p++) {
879 size_t f_len, p_len, i;
881 if (!full)
return -1;
883 f_len = strlen(full);
885 if (!part)
return -1;
887 p_len = strlen(part);
888 if (!p_len)
return f_len;
890 if ((f_len < p_len) || !f_len)
return -1;
892 for (i = 0; i < p_len; i++)
if (part[p_len - 1 - i] != full[f_len - 1 - i])
return -1;
894 return f_len - p_len;
910 char const *
const *dn_list)
913 char const *
const *dn_p;
916 for (dn_p = dn_list; *dn_p; dn_p++) {
920 len = (strlen(*dn_p) * 3) + 1;
921 MEM(escaped = talloc_array(ctx,
char, len));
923 MEM(
out = talloc_asprintf_append_buffer(
out,
"(%s=%s)", dn_attr, escaped));
926 MEM(
out = talloc_strdup_append_buffer(
out,
")"));
928 if (filter && *filter) {
951 char const *
in = NULL;
962 for (i = 0; i < sublen; i++) {
963 if (sub[i] && *sub[i]) {
966 len += strlen(sub[i]);
976 buffer = talloc_array(ctx,
char, len + 4);
979 for (i = 0; i < sublen; i++) {
980 if (sub[i] && (*sub[i] !=
'\0')) {
1014 if (!attr)
return -1;
1016 len = talloc_array_length(attrs);
1018 for (i = 0; i < len; i++) {
1019 if (!attrs[i])
continue;
1020 if (
strcasecmp(attrs[i], attr) == 0)
return 1;
1021 if (
strcasecmp(attrs[i],
"*") == 0)
return 1;
1038 LDAPURLDesc *ldap_url;
1039 bool set_port_maybe =
true;
1040 int default_port = LDAP_PORT;
1045 if (ldap_url_parse(server, &ldap_url)) {
1046 cf_log_err(ci,
"Parsing LDAP URL \"%s\" failed", server);
1048 ldap_free_urldesc(ldap_url);
1052 if (ldap_url->lud_dn && (ldap_url->lud_dn[0] !=
'\0')) {
1053 cf_log_err(ci,
"Base DN cannot be specified via server URL");
1054 goto ldap_url_error;
1057 if (ldap_url->lud_attrs && ldap_url->lud_attrs[0]) {
1058 cf_log_err(ci,
"Attribute list cannot be speciried via server URL");
1059 goto ldap_url_error;
1065 if (ldap_url->lud_scope != LDAP_SCOPE_BASE) {
1066 cf_log_err(ci,
"Scope cannot be specified via server URL");
1067 goto ldap_url_error;
1069 ldap_url->lud_scope = -1;
1076 if ((p = strchr(server,
']')) && (p[1] ==
':')) {
1077 set_port_maybe =
false;
1078 }
else if ((p = strchr(server,
':')) && (strchr(p+1,
':') != NULL)) {
1079 set_port_maybe =
false;
1085 if (ldap_url->lud_scheme) {
1086 if (strcmp(ldap_url->lud_scheme,
"ldaps") == 0) {
1088 cf_log_err(ci,
"ldaps:// scheme is not compatible with 'start_tls'");
1089 goto ldap_url_error;
1091 default_port = LDAPS_PORT;
1092 handle_config->
tls_mode = LDAP_OPT_X_TLS_HARD;
1093 }
else if (strcmp(ldap_url->lud_scheme,
"ldapi") == 0) {
1094 set_port_maybe =
false;
1098 if (set_port_maybe) {
1102 ldap_url->lud_port = handle_config->
port;
1109 if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
1112 url = ldap_url_desc2str(ldap_url);
1114 cf_log_err(ci,
"Failed recombining URL components");
1115 goto ldap_url_error;
1117 handle_config->
server = talloc_asprintf_append(handle_config->
server,
"%s ",
url);
1119 ldap_free_urldesc(ldap_url);
1140 port = handle_config->
port;
1146 if (strchr(server,
'/')) {
1150 cf_log_err(ci,
"Invalid 'server' entry, must be in format <server>[:<port>] or "
1151 "an ldap URI (ldap|cldap|ldaps|ldapi)://<server>:<port>");
1155 p = strrchr(server,
':');
1157 port = (int)strtol((p + 1), &q, 10);
1158 if ((p == server) || ((p + 1) == q) || (*q !=
'\0'))
goto bad_server_fmt;
1161 len = strlen(server);
1163 if (port == 0) port = LDAP_PORT;
1165 handle_config->
server = talloc_asprintf_append(handle_config->
server,
"ldap://%.*s:%i ",
1166 (
int)len, server, port);
1176 switch (ldap_url_err) {
1177 case LDAP_URL_SUCCESS:
1180 case LDAP_URL_ERR_MEM:
1183 case LDAP_URL_ERR_PARAM:
1184 return "parameter is bad";
1186 case LDAP_URL_ERR_BADSCHEME:
1187 return "URL doesn't begin with \"[c]ldap[si]://\"";
1189 case LDAP_URL_ERR_BADENCLOSURE:
1190 return "URL is missing trailing \">\"";
1192 case LDAP_URL_ERR_BADURL:
1193 return "URL is bad";
1195 case LDAP_URL_ERR_BADHOST:
1196 return "host/port is bad";
1198 case LDAP_URL_ERR_BADATTRS:
1199 return "bad (or missing) attributes";
1201 case LDAP_URL_ERR_BADSCOPE:
1202 return "scope string is invalid (or missing)";
1204 case LDAP_URL_ERR_BADFILTER:
1205 return "bad or missing filter";
1207 case LDAP_URL_ERR_BADEXTS:
1208 return "bad or missing extensions";
1211 return "unknown reason";
1224 BerElement *ber = NULL;
1226 struct berval **vals;
1231 msgtype = ldap_msgtype(entry);
1233 case LDAP_RES_SEARCH_ENTRY:
1234 dn = ldap_get_dn(ld, entry);
1236 DEBUG(
"dn: %s", dn);
1240 for (attr = ldap_first_attribute(ld, entry, &ber);
1242 attr = ldap_next_attribute(ld, entry, ber)) {
1243 vals = ldap_get_values_len(ld, entry, attr);
1245 DEBUG(
"%s: no values", attr);
1250 for (i = 0; vals[i] != NULL; i++) {
1251 bool binary =
false;
1254 for (j = 0; j < vals[i]->bv_len; j++) {
1255 char c = vals[i]->bv_val[j];
1256 if ((c < 32) || (c > 126)) {
1270 ldap_value_free_len(vals);
1275 case LDAP_RES_SEARCH_RESULT:
1277 case LDAP_RES_MODIFY:
1279 case LDAP_RES_DELETE:
1280 case LDAP_RES_COMPARE:
1281 case LDAP_RES_EXTENDED:
1284 char *matched = NULL;
1285 char *errmsg = NULL;
1288 rc = ldap_parse_result(ld, entry, &msgtype, &matched, &errmsg, &refs, NULL, 0);
1289 if (rc != LDAP_SUCCESS) {
1290 DEBUG(
"failed to parse result: %s", ldap_err2string(rc));
1294 DEBUG(
"result code: %d (%s)", msgtype, ldap_err2string(msgtype));
1296 if (matched && *matched) {
1297 DEBUG(
"matched DN: %s", matched);
1299 if (errmsg && *errmsg) {
1300 DEBUG(
"error message: %s", errmsg);
1303 for (i = 0; refs[i] != NULL; i++) {
1304 DEBUG(
"referral: %s", refs[i]);
1308 if (matched) ldap_memfree(matched);
1309 if (errmsg) ldap_memfree(errmsg);
1310 if (refs) ldap_memvfree((
void **)refs);
1315 DEBUG(
"unhandled LDAP message type: %d", msgtype);
1319 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 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.
ber_len_t len
Length of the current element.
char * last
End marker of the value set.
char * server
Initial server to bind to.
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)
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.
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[]
char * fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
static const char filter_specials[]
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)
size_t fr_ldap_dn_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Escape a string 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.
size_t fr_ldap_filter_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Escape a string for use as an RFC 4515 filter assertion value.
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)
@ FR_TYPE_STRING
String of printable characters.
int strncasecmp(char *s1, char *s2, int n)
int strcasecmp(char *s1, char *s2)
static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
static char const * url[FR_RADIUS_FAIL_MAX+1]
static int8_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.
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(_start, _len_or_end)
#define fr_sbuff_current(_sbuff_or_marker)
#define fr_sbuff_buff(_sbuff_or_marker)
#define FR_SBUFF_IN_STR(_start)
#define fr_sbuff_out(_err, _out, _in)
#define fr_sbuff_remaining(_sbuff_or_marker)
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 * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
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 * talloc_typed_strdup(TALLOC_CTX *ctx, char const *p)
Call talloc_strdup, setting the type on the new chunk correctly.
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_printf_push(_fmt,...)
Add a message to an existing stack of messages at the tail.
#define fr_strerror_const(_msg)
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
void fr_value_box_strdup_shallow_replace(fr_value_box_t *vb, char const *src, ssize_t len)
Free the existing buffer (if talloced) associated with the valuebox, and replace it with a new one.
#define fr_box_strvalue_len(_val, _len)
#define fr_value_box_is_safe_for(_box, _safe_for)
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out
#define fr_box_octets(_val, _len)