26RCSID(
"$Id: 6f05a057d11971431647e8f0c77a2daa5807ea3b $")
 
   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";
 
  109        return outlen - left;
 
 
  124        if (!fr_sbuff_init_talloc(vb, &sbuff, &sbuff_ctx, vb->vb_length * 3, vb->vb_length * 3)) {
 
  134        if (len == vb->vb_length) {
 
 
  163        size_t  freespace = outlen;
 
  165        if (outlen <= 1) 
return 0;
 
  168        while (*p && (--freespace > 0)) {
 
  184                if (!(c1 = memchr(
hextab, tolower(p[0]), 16)) ||
 
  185                    !(c2 = memchr(
hextab, tolower(p[1]), 16))) 
goto next;
 
  194        return outlen - freespace;
 
 
  211        bool too_soon = 
true;
 
  223                        if (
inlen < 2) 
return false;
 
  246                        if (
inlen < 3) 
return false;
 
  265                        if (too_soon || (*p != want)) 
return false;     
 
  271                        if (too_soon || (*p != want)) 
return false;     
 
  289        if (too_soon || (
comp < 2)) 
return false;
 
 
  306        LDAPControl **sss_p = sss, **sss_end = sss_p + sss_len;
 
  317        for (i = 0; extensions[i]; i++) {
 
  319                bool            is_critical = 
false;
 
  321                if (sss_p == sss_end) {
 
  338                                                  "in the format \"[!]sss=<key>[,key]\"");
 
  342                                        if (*s) ldap_control_free(*s);
 
  349                        if (ret != LDAP_SUCCESS) {
 
  355                        if (*sss_p) ldap_control_free(*sss_p);
 
  358                        ldap_free_sort_keylist(keys);
 
  359                        if (ret != LDAP_SUCCESS) {
 
  361                                                   ldap_err2string(ret));
 
  372                        struct berval   attr_value;
 
  378                                                  "in the format \"[!]vlv=<before>/<after>(/<offset>/<count>|:<value>)");
 
  382                        vlvinfo.ldvlv_context = NULL;
 
  384                        if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) 
goto vlv_error;
 
  386                        vlvinfo.ldvlv_before_count = ext_value;
 
  388                        if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) 
goto vlv_error;
 
  389                        vlvinfo.ldvlv_after_count = ext_value;
 
  394                                vlvinfo.ldvlv_attrvalue = NULL;
 
  396                                if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) 
goto vlv_error;
 
  398                                vlvinfo.ldvlv_offset = ext_value;
 
  400                                if (
fr_sbuff_out(NULL, &ext_value, &sbuff) <= 0) 
goto vlv_error;
 
  401                                vlvinfo.ldvlv_count = ext_value;
 
  407                                vlvinfo.ldvlv_attrvalue = &attr_value;
 
  413                        if (ret != LDAP_SUCCESS) {
 
  415                                                   ldap_err2string(ret));
 
  428        return (sss_end - sss_p);
 
 
  447        out = talloc_array(ctx, 
char, 
in->bv_len + 1);
 
  448        if (!
out) 
return NULL;
 
  450        memcpy(
out, 
in->bv_val, 
in->bv_len);
 
  451        out[
in->bv_len] = 
'\0';
 
 
  467        if (!
out) 
return NULL;
 
  469        memcpy(
out, 
in->bv_val, 
in->bv_len);
 
 
  497        for (p = 
in; *p != 
'\0'; p++) {
 
 
  543        size_t f_len, p_len, i;
 
  545        if (!full) 
return -1;
 
  547        f_len = strlen(full);
 
  549        if (!part) 
return -1;
 
  551        p_len = strlen(part);
 
  552        if (!p_len) 
return f_len;
 
  554        if ((f_len < p_len) || !f_len) 
return -1;
 
  556        for (i = 0; i < p_len; i++) 
if (part[p_len - i] != full[f_len - i]) 
return -1;
 
  558        return f_len - p_len;
 
 
  573        char const      *
in = NULL;
 
  584        for (i = 0; i < sublen; i++) {
 
  585                if (sub[i] && *sub[i]) {
 
  588                        len += strlen(sub[i]);
 
  598                buffer = talloc_array(ctx, 
char, len + 4);
 
  601                for (i = 0; i < sublen; i++) {
 
  602                        if (sub[i] && (*sub[i] != 
'\0')) {
 
 
  636        if (!attr) 
return -1;
 
  638        len = talloc_array_length(attrs);
 
  640        for (i = 0; i < len; i++) {
 
  641                if (!attrs[i]) 
continue;
 
  642                if (
strcasecmp(attrs[i], attr) == 0) 
return 1;
 
 
  660        LDAPURLDesc     *ldap_url;
 
  661        bool            set_port_maybe = 
true;
 
  662        int             default_port = LDAP_PORT;
 
  666        if (ldap_url_parse(server, &ldap_url)) {
 
  667                cf_log_err(ci, 
"Parsing LDAP URL \"%s\" failed", server);
 
  669                ldap_free_urldesc(ldap_url);
 
  673        if (ldap_url->lud_dn && (ldap_url->lud_dn[0] != 
'\0')) {
 
  674                cf_log_err(ci, 
"Base DN cannot be specified via server URL");
 
  678        if (ldap_url->lud_attrs && ldap_url->lud_attrs[0]) {
 
  679                cf_log_err(ci, 
"Attribute list cannot be speciried via server URL");
 
  686        if (ldap_url->lud_scope != LDAP_SCOPE_BASE) {
 
  687                cf_log_err(ci, 
"Scope cannot be specified via server URL");
 
  690        ldap_url->lud_scope = -1;       
 
  697        if ((p = strchr(server, 
']')) && (p[1] == 
':')) {                       
 
  698                set_port_maybe = 
false;
 
  699        } 
else if ((p = strchr(server, 
':')) && (strchr(p+1, 
':') != NULL)) {   
 
  700                set_port_maybe = 
false;
 
  706        if (ldap_url->lud_scheme) {
 
  707                if (strcmp(ldap_url->lud_scheme, 
"ldaps") == 0) {
 
  709                                cf_log_err(ci, 
"ldaps:// scheme is not compatible with 'start_tls'");
 
  712                        default_port = LDAPS_PORT;
 
  713                        handle_config->
tls_mode = LDAP_OPT_X_TLS_HARD;
 
  714                } 
else if (strcmp(ldap_url->lud_scheme, 
"ldapi") == 0) {
 
  715                        set_port_maybe = 
false;
 
  719        if (set_port_maybe) {
 
  723                ldap_url->lud_port = handle_config->
port;
 
  730                if (!ldap_url->lud_port) ldap_url->lud_port = default_port;
 
  733        url = ldap_url_desc2str(ldap_url);
 
  735                cf_log_err(ci, 
"Failed recombining URL components");
 
  738        handle_config->
server = talloc_asprintf_append(handle_config->
server, 
"%s ", url);
 
  740        ldap_free_urldesc(ldap_url);
 
 
  761        port = handle_config->
port;
 
  767        if (strchr(server, 
'/')) {
 
  771                cf_log_err(ci, 
"Invalid 'server' entry, must be in format <server>[:<port>] or " 
  772                               "an ldap URI (ldap|cldap|ldaps|ldapi)://<server>:<port>");
 
  776        p = strrchr(server, 
':');
 
  778                port = (int)strtol((p + 1), &q, 10);
 
  779                if ((p == server) || ((p + 1) == q) || (*q != 
'\0')) 
goto bad_server_fmt;
 
  782                len = strlen(server);
 
  784        if (port == 0) port = LDAP_PORT;
 
  786        handle_config->
server = talloc_asprintf_append(handle_config->
server, 
"ldap://%.*s:%i ",
 
  787                                                       (
int)len, server, port);
 
 
  797        switch (ldap_url_err) {
 
  798        case LDAP_URL_SUCCESS:
 
  801        case LDAP_URL_ERR_MEM:
 
  804        case LDAP_URL_ERR_PARAM:
 
  805                return "parameter is bad";
 
  807        case LDAP_URL_ERR_BADSCHEME:
 
  808                return "URL doesn't begin with \"[c]ldap[si]://\"";
 
  810        case LDAP_URL_ERR_BADENCLOSURE:
 
  811                return "URL is missing trailing \">\"";
 
  813        case LDAP_URL_ERR_BADURL:
 
  816        case LDAP_URL_ERR_BADHOST:
 
  817                return "host/port is bad";
 
  819        case LDAP_URL_ERR_BADATTRS:
 
  820                return "bad (or missing) attributes";
 
  822        case LDAP_URL_ERR_BADSCOPE:
 
  823                return "scope string is invalid (or missing)";
 
  825        case LDAP_URL_ERR_BADFILTER:
 
  826                return "bad or missing filter";
 
  828        case LDAP_URL_ERR_BADEXTS:
 
  829                return "bad or missing extensions";
 
  832                return "unknown reason";
 
 
  845        BerElement      *ber = NULL;
 
  847        struct berval   **vals;
 
  852        msgtype = ldap_msgtype(entry);
 
  854        case LDAP_RES_SEARCH_ENTRY:
 
  855                dn = ldap_get_dn(ld, entry);
 
  861                for (attr = ldap_first_attribute(ld, entry, &ber);
 
  863                     attr = ldap_next_attribute(ld, entry, ber)) {
 
  864                        vals = ldap_get_values_len(ld, entry, attr);
 
  866                                DEBUG(
"%s: no values", attr);
 
  871                        for (i = 0; vals[i] != NULL; i++) {
 
  875                                for (j = 0; j < vals[i]->bv_len; j++) {
 
  876                                        char c = vals[i]->bv_val[j];
 
  877                                        if ((c < 32) || (c > 126)) {
 
  891                        ldap_value_free_len(vals);
 
  896        case LDAP_RES_SEARCH_RESULT:
 
  898        case LDAP_RES_MODIFY:
 
  900        case LDAP_RES_DELETE:
 
  901        case LDAP_RES_COMPARE:
 
  902        case LDAP_RES_EXTENDED:
 
  905                char *matched = NULL;
 
  909                rc = ldap_parse_result(ld, entry, &msgtype, &matched, &errmsg, &refs, NULL, 0);
 
  910                if (rc != LDAP_SUCCESS) {
 
  911                        DEBUG(
"failed to parse result: %s", ldap_err2string(rc));
 
  915                DEBUG(
"result code: %d (%s)", msgtype, ldap_err2string(msgtype));
 
  917                if (matched && *matched) {
 
  918                        DEBUG(
"matched DN: %s", matched);
 
  920                if (errmsg && *errmsg) {
 
  921                        DEBUG(
"error message: %s", errmsg);
 
  924                        for (i = 0; refs[i] != NULL; i++) {
 
  925                                DEBUG(
"referral: %s", refs[i]);
 
  929                if (matched) ldap_memfree(matched);
 
  930                if (errmsg) ldap_memfree(errmsg);
 
  931                if (refs) ldap_memvfree((
void **)refs);
 
  936                DEBUG(
"unhandled LDAP message type: %d", msgtype);
 
  940        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.
char * server
Initial server to bind to.
bool start_tls
Send the Start TLS message to the LDAP directory to start encrypted communications using the standard...
uint16_t port
Port to use when binding to the server.
Connection configuration.
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...
static const char hextab[]
size_t fr_ldap_util_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
size_t fr_ldap_uri_escape_func(UNUSED request_t *request, char *out, size_t outlen, char const *in, UNUSED void *arg)
Converts "bad" strings into ones which are safe for LDAP.
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.
int fr_ldap_attrs_check(char const **attrs, char const *attr)
Check that a particular attribute is included in an attribute list.
static USES_APPLE_DEPRECATED_API const char specials[]
uint8_t * fr_ldap_berval_to_bin(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced buffer.
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.
char * fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
int fr_ldap_box_escape(fr_value_box_t *vb, UNUSED void *uctx)
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.
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.
static const bool escapes[UINT8_MAX+1]
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.
#define EMARKER(_str, _marker_idx, _marker)
@ FR_TYPE_STRING
String of printable characters.
int strcasecmp(char *s1, char *s2)
static int encode(bio_handle_t *h, request_t *request, bio_request_t *u, uint8_t id)
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.
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)