diff --git modules/ldapbackend/native.cc modules/ldapbackend/native.cc index 4ac7ea33c..d86f4f5e5 100644 --- modules/ldapbackend/native.cc +++ modules/ldapbackend/native.cc @@ -279,11 +279,11 @@ void LdapBackend::lookup_tree(const QType& qtype, const DNSName& qname, DNSPacke filter = strbind(":target:", filter, getArg("filter-lookup")); stringtok(parts, toLower(qname.toString()), "."); for (auto i = parts.crbegin(); i != parts.crend(); i++) { - dn = "dc=" + *i + "," + dn; + dn = "dc=" + d_pldap->escape(*i) + "," + dn; } g_log << Logger::Debug << d_myname << " Search = basedn: " << dn + getArg("basedn") << ", filter: " << filter << ", qtype: " << qtype.toString() << endl; d_search = d_pldap->search(dn + getArg("basedn"), LDAP_SCOPE_BASE, filter, attributes); } diff --git modules/ldapbackend/powerldap.cc modules/ldapbackend/powerldap.cc index edd97f0c5..4363d0256 100644 --- modules/ldapbackend/powerldap.cc +++ modules/ldapbackend/powerldap.cc @@ -390,24 +390,70 @@ void PowerLDAP::getSearchResults(int msgid, sresult_t& result, bool dn) const string PowerLDAP::getError(int rc) { return ldapGetError(d_ld, rc); } -const string PowerLDAP::escape(const string& str) +// Escape sensitive characters according to the rules in RFC4514, section 2.4 +// and RFC4515, section 3. +const std::string PowerLDAP::escape(const string& input) { - string a; - string::const_iterator i; - char tmp[4]; - - for (i = str.begin(); i != str.end(); i++) { - // RFC4515 3 - if ((unsigned char)*i == '*' || (unsigned char)*i == '(' || (unsigned char)*i == ')' || (unsigned char)*i == '\\' || (unsigned char)*i == '\0' || (unsigned char)*i > 127) { - snprintf(tmp, sizeof(tmp), "\\%02x", (unsigned char)*i); - - a += tmp; + std::string out; + std::array hexbuf{}; + auto length = input.length(); + + out.reserve(length); + for (decltype(length) pos = 0; pos < length; ++pos) { + uint8_t chr = static_cast(input[pos]); + // Perform UTF-8 encoding of 8-bit values if needed + if (chr >= 0x80) { + ::snprintf(hexbuf.data(), hexbuf.size(), "\\%02X", + static_cast(0xc0 | ((chr >> 6) & 0x3f))); + out.append(hexbuf.data()); + ::snprintf(hexbuf.data(), hexbuf.size(), "\\%02X", + static_cast(0x80 | (chr & 0x3f))); + out.append(hexbuf.data()); + } + else { + bool escape4514{false}; + bool escape4515{false}; + // Characters which need escaping regardless of their position + switch (chr) { + case '"': + case '+': + case ',': + case ';': + case '<': + case '>': + escape4514 = true; + break; + case '*': + case '(': + case ')': + case '\\': + case '\0': + escape4515 = true; + break; + default: + break; + } + // Characters which need escaping if in first position + if (pos == 0) { + escape4514 |= chr == ' ' || chr == '#'; + } + // Characters which need escaping if in last position + if (pos == length - 1) { + escape4514 |= chr == ' '; + } + if (escape4515) { + ::snprintf(hexbuf.data(), hexbuf.size(), "\\%02X", chr); + out.append(hexbuf.data()); + } + else { + if (escape4514) { + out.append(1, '\\'); + } + out.append(1, chr); + } } - else - a += *i; } - - return a; + return out; }