feat: Implement LDAP bind/whoami

This commit is contained in:
selfhoster selfhoster 2026-09-01 21:18:19 +02:00
commit b4330b37fa
19 changed files with 664 additions and 37 deletions

6
vendor/dn_escape/Cargo.toml vendored Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "dn_escape"
version = "0.1.0"
edition = "2024"
[dependencies]

22
vendor/dn_escape/MIT_LICENSE vendored Normal file
View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2017 Ivan Nejgebauer <inejge@gmail.com>
Copyright (c) 2014-2017 Gregor Reitzenstein <dean4devil@paranoidlabs.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

4
vendor/dn_escape/README.md vendored Normal file
View file

@ -0,0 +1,4 @@
# dn_escape
Borrowed from the ldap3 project at version v0.12.1, under MIT license. A copy
of the license can be found in [MIT_LICENSE](MIT_LICENSE).

69
vendor/dn_escape/src/lib.rs vendored Normal file
View file

@ -0,0 +1,69 @@
// CODE DEVELOPED BY THE LDAP3 PROJECT, UNDER MIT LICENSE.
use std::borrow::Cow;
/// Escape an attribute value in a relative distinguished name (RDN).
///
/// When a literal string is used to represent an attribute value in an RDN,
/// some of its characters might need to be escaped according to the rules
/// of [RFC 4514](https://tools.ietf.org/html/rfc4514).
///
/// The function is named `dn_escape()` instead of `rdn_escape()` because of
/// a long-standing association of its intended use with the handling of DNs.
///
/// The argument, `val`, can be owned or borrowed. The function doesn't
/// allocate the return value unless there's need to escape the input.
pub fn dn_escape<'a, S: Into<Cow<'a, str>>>(val: S) -> Cow<'a, str> {
#[inline]
fn always_escape(c: u8) -> bool {
c == b'"'
|| c == b'+'
|| c == b','
|| c == b';'
|| c == b'<'
|| c == b'='
|| c == b'>'
|| c == b'\\'
|| c == 0
}
#[inline]
fn escape_leading(c: u8) -> bool {
c == b' ' || c == b'#'
}
#[inline]
fn escape_trailing(c: u8) -> bool {
c == b' '
}
#[inline]
fn xdigit(c: u8) -> u8 {
c + if c < 10 { b'0' } else { b'a' - 10 }
}
let val = val.into();
let mut output = None;
for (i, &c) in val.as_bytes().iter().enumerate() {
if always_escape(c)
|| i == 0 && escape_leading(c)
|| i + 1 == val.len() && escape_trailing(c)
{
if output.is_none() {
output = Some(Vec::with_capacity(val.len() + 12)); // guess: up to 4 escaped chars
output.as_mut().unwrap().extend(val[..i].as_bytes());
}
let output = output.as_mut().unwrap();
output.push(b'\\');
output.push(xdigit(c >> 4));
output.push(xdigit(c & 0xF));
} else if let Some(ref mut output) = output {
output.push(c);
}
}
if let Some(output) = output {
Cow::Owned(String::from_utf8(output).expect("dn escaped"))
} else {
val
}
}