2022-10-01 08:08:51 +02:00
|
|
|
use std::net;
|
2023-09-29 04:02:13 +02:00
|
|
|
use std::pin::Pin;
|
2022-10-01 08:08:51 +02:00
|
|
|
use std::str::FromStr;
|
2020-06-10 04:07:43 +02:00
|
|
|
|
2022-10-05 01:48:48 +02:00
|
|
|
use crate::actors::v1_read::QueryServerReadV1;
|
2020-09-06 00:44:35 +02:00
|
|
|
use futures_util::sink::SinkExt;
|
2020-06-10 04:07:43 +02:00
|
|
|
use futures_util::stream::StreamExt;
|
2022-12-28 08:52:25 +01:00
|
|
|
use kanidmd_lib::idm::ldap::{LdapBoundToken, LdapResponseState};
|
2022-10-05 01:48:48 +02:00
|
|
|
use kanidmd_lib::prelude::*;
|
2022-10-01 08:08:51 +02:00
|
|
|
use ldap3_proto::proto::LdapMsg;
|
|
|
|
use ldap3_proto::LdapCodec;
|
2023-09-26 01:59:00 +02:00
|
|
|
use openssl::ssl::{Ssl, SslAcceptor};
|
2023-09-29 04:02:13 +02:00
|
|
|
use tokio::net::{TcpListener, TcpStream};
|
2022-10-01 08:08:51 +02:00
|
|
|
use tokio_openssl::SslStream;
|
2020-09-06 00:44:35 +02:00
|
|
|
use tokio_util::codec::{FramedRead, FramedWrite};
|
2020-06-10 04:07:43 +02:00
|
|
|
|
2022-11-23 11:10:43 +01:00
|
|
|
use crate::CoreAction;
|
|
|
|
use tokio::sync::broadcast;
|
|
|
|
|
2020-09-06 00:44:35 +02:00
|
|
|
struct LdapSession {
|
2020-06-10 04:07:43 +02:00
|
|
|
uat: Option<LdapBoundToken>,
|
|
|
|
}
|
|
|
|
|
2020-09-06 00:44:35 +02:00
|
|
|
impl LdapSession {
|
|
|
|
fn new() -> Self {
|
|
|
|
LdapSession {
|
|
|
|
// We start un-authenticated
|
|
|
|
uat: None,
|
|
|
|
}
|
|
|
|
}
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
|
|
|
|
2022-02-20 03:43:38 +01:00
|
|
|
#[instrument(name = "ldap-request", skip(client_address, qe_r_ref))]
|
|
|
|
async fn client_process_msg(
|
|
|
|
uat: Option<LdapBoundToken>,
|
|
|
|
client_address: net::SocketAddr,
|
|
|
|
protomsg: LdapMsg,
|
|
|
|
qe_r_ref: &'static QueryServerReadV1,
|
|
|
|
) -> Option<LdapResponseState> {
|
2022-08-09 05:07:06 +02:00
|
|
|
let eventid = sketching::tracing_forest::id();
|
2022-02-20 03:43:38 +01:00
|
|
|
security_info!(
|
|
|
|
client_ip = %client_address.ip(),
|
|
|
|
client_port = %client_address.port(),
|
|
|
|
"LDAP client"
|
|
|
|
);
|
|
|
|
qe_r_ref.handle_ldaprequest(eventid, protomsg, uat).await
|
|
|
|
}
|
|
|
|
|
2023-09-29 04:02:13 +02:00
|
|
|
async fn client_process(
|
|
|
|
tcpstream: TcpStream,
|
|
|
|
tls_acceptor: SslAcceptor,
|
2021-08-10 04:16:13 +02:00
|
|
|
client_address: net::SocketAddr,
|
2020-09-06 00:44:35 +02:00
|
|
|
qe_r_ref: &'static QueryServerReadV1,
|
|
|
|
) {
|
2023-09-29 04:02:13 +02:00
|
|
|
// Start the event
|
|
|
|
// From the parameters we need to create an SslContext.
|
|
|
|
let mut tlsstream = match Ssl::new(tls_acceptor.context())
|
|
|
|
.and_then(|tls_obj| SslStream::new(tls_obj, tcpstream))
|
|
|
|
{
|
|
|
|
Ok(ta) => ta,
|
|
|
|
Err(e) => {
|
|
|
|
error!("LDAP TLS setup error, continuing -> {:?}", e);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if let Err(e) = SslStream::accept(Pin::new(&mut tlsstream)).await {
|
|
|
|
error!("LDAP TLS accept error, continuing -> {:?}", e);
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
let (r, w) = tokio::io::split(tlsstream);
|
2023-11-29 01:43:15 +01:00
|
|
|
let mut r = FramedRead::new(r, LdapCodec::default());
|
|
|
|
let mut w = FramedWrite::new(w, LdapCodec::default());
|
2023-09-29 04:02:13 +02:00
|
|
|
|
2021-08-10 04:16:13 +02:00
|
|
|
// This is a connected client session. we need to associate some state to the session
|
2020-09-06 00:44:35 +02:00
|
|
|
let mut session = LdapSession::new();
|
2021-08-10 04:16:13 +02:00
|
|
|
// Now that we have the session we begin an event loop to process input OR we return.
|
2020-09-06 00:44:35 +02:00
|
|
|
while let Some(Ok(protomsg)) = r.next().await {
|
|
|
|
// Start the event
|
|
|
|
let uat = session.uat.clone();
|
2023-01-25 07:09:54 +01:00
|
|
|
let caddr = client_address;
|
2020-09-06 00:44:35 +02:00
|
|
|
|
2022-02-20 03:43:38 +01:00
|
|
|
match client_process_msg(uat, caddr, protomsg, qe_r_ref).await {
|
|
|
|
// I'd really have liked to have put this near the [LdapResponseState::Bind] but due
|
|
|
|
// to the handing of `audit` it isn't possible due to borrows, etc.
|
2020-09-06 00:44:35 +02:00
|
|
|
Some(LdapResponseState::Unbind) => return,
|
|
|
|
Some(LdapResponseState::Disconnect(rmsg)) => {
|
2020-09-08 04:46:10 +02:00
|
|
|
if w.send(rmsg).await.is_err() {
|
2020-09-06 00:44:35 +02:00
|
|
|
break;
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
2020-09-06 00:44:35 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Some(LdapResponseState::Bind(uat, rmsg)) => {
|
|
|
|
session.uat = Some(uat);
|
2020-09-08 04:46:10 +02:00
|
|
|
if w.send(rmsg).await.is_err() {
|
2020-09-06 00:44:35 +02:00
|
|
|
break;
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
2020-09-06 00:44:35 +02:00
|
|
|
}
|
|
|
|
Some(LdapResponseState::Respond(rmsg)) => {
|
2020-09-08 04:46:10 +02:00
|
|
|
if w.send(rmsg).await.is_err() {
|
2020-09-06 00:44:35 +02:00
|
|
|
break;
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
2020-09-06 00:44:35 +02:00
|
|
|
}
|
|
|
|
Some(LdapResponseState::MultiPartResponse(v)) => {
|
|
|
|
for rmsg in v.into_iter() {
|
2020-09-08 04:46:10 +02:00
|
|
|
if w.send(rmsg).await.is_err() {
|
2020-09-06 00:44:35 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
2020-09-06 00:44:35 +02:00
|
|
|
}
|
|
|
|
Some(LdapResponseState::BindMultiPartResponse(uat, v)) => {
|
|
|
|
session.uat = Some(uat);
|
|
|
|
for rmsg in v.into_iter() {
|
2020-09-08 04:46:10 +02:00
|
|
|
if w.send(rmsg).await.is_err() {
|
2020-09-06 00:44:35 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
2020-09-06 00:44:35 +02:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
error!("Internal server error");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-10 04:16:13 +02:00
|
|
|
/// TLS LDAP Listener, hands off to [client_process]
|
2020-09-06 00:44:35 +02:00
|
|
|
async fn tls_acceptor(
|
2021-01-10 04:41:56 +01:00
|
|
|
listener: TcpListener,
|
2023-09-29 04:02:13 +02:00
|
|
|
tls_acceptor: SslAcceptor,
|
2020-09-06 00:44:35 +02:00
|
|
|
qe_r_ref: &'static QueryServerReadV1,
|
2022-11-23 11:10:43 +01:00
|
|
|
mut rx: broadcast::Receiver<CoreAction>,
|
2020-09-06 00:44:35 +02:00
|
|
|
) {
|
|
|
|
loop {
|
2022-11-23 11:10:43 +01:00
|
|
|
tokio::select! {
|
|
|
|
Ok(action) = rx.recv() => {
|
|
|
|
match action {
|
|
|
|
CoreAction::Shutdown => break,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
accept_result = listener.accept() => {
|
|
|
|
match accept_result {
|
|
|
|
Ok((tcpstream, client_socket_addr)) => {
|
2023-09-29 04:02:13 +02:00
|
|
|
let clone_tls_acceptor = tls_acceptor.clone();
|
|
|
|
tokio::spawn(client_process(tcpstream, clone_tls_acceptor, client_socket_addr, qe_r_ref));
|
2022-11-23 11:10:43 +01:00
|
|
|
}
|
2020-09-06 00:44:35 +02:00
|
|
|
Err(e) => {
|
2022-11-23 11:10:43 +01:00
|
|
|
error!("LDAP acceptor error, continuing -> {:?}", e);
|
2020-09-06 00:44:35 +02:00
|
|
|
}
|
2022-11-23 11:10:43 +01:00
|
|
|
}
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-08 05:08:46 +02:00
|
|
|
info!("Stopped {}", super::TaskName::LdapActor);
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) async fn create_ldap_server(
|
|
|
|
address: &str,
|
2023-09-26 01:59:00 +02:00
|
|
|
opt_ssl_acceptor: Option<SslAcceptor>,
|
2020-09-06 00:44:35 +02:00
|
|
|
qe_r_ref: &'static QueryServerReadV1,
|
2022-11-23 11:10:43 +01:00
|
|
|
rx: broadcast::Receiver<CoreAction>,
|
|
|
|
) -> Result<tokio::task::JoinHandle<()>, ()> {
|
2021-04-26 03:52:13 +02:00
|
|
|
if address.starts_with(":::") {
|
|
|
|
// takes :::xxxx to xxxx
|
|
|
|
let port = address.replacen(":::", "", 1);
|
2022-10-18 11:15:22 +02:00
|
|
|
error!("Address '{}' looks like an attempt to wildcard bind with IPv6 on port {} - please try using ldapbindaddress = '[::]:{}'", address, port, port);
|
2021-04-26 03:52:13 +02:00
|
|
|
};
|
|
|
|
|
2020-06-10 04:07:43 +02:00
|
|
|
let addr = net::SocketAddr::from_str(address).map_err(|e| {
|
2022-10-18 11:15:22 +02:00
|
|
|
error!("Could not parse LDAP server address {} -> {:?}", address, e);
|
2020-06-10 04:07:43 +02:00
|
|
|
})?;
|
|
|
|
|
2020-09-06 00:44:35 +02:00
|
|
|
let listener = TcpListener::bind(&addr).await.map_err(|e| {
|
2022-10-18 11:15:22 +02:00
|
|
|
error!(
|
2022-09-21 05:36:58 +02:00
|
|
|
"Could not bind to LDAP server address {} -> {:?}",
|
2020-08-04 04:58:11 +02:00
|
|
|
address, e
|
|
|
|
);
|
2020-09-06 00:44:35 +02:00
|
|
|
})?;
|
2020-06-10 04:07:43 +02:00
|
|
|
|
2023-09-26 01:59:00 +02:00
|
|
|
let ldap_acceptor_handle = match opt_ssl_acceptor {
|
|
|
|
Some(ssl_acceptor) => {
|
2022-10-18 11:15:22 +02:00
|
|
|
info!("Starting LDAPS interface ldaps://{} ...", address);
|
2023-09-26 01:59:00 +02:00
|
|
|
|
|
|
|
tokio::spawn(tls_acceptor(listener, ssl_acceptor, qe_r_ref, rx))
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
|
|
|
None => {
|
2022-10-18 11:15:22 +02:00
|
|
|
error!("The server won't run without TLS!");
|
2022-09-21 05:36:58 +02:00
|
|
|
return Err(());
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|
2022-11-23 11:10:43 +01:00
|
|
|
};
|
2020-06-10 04:07:43 +02:00
|
|
|
|
|
|
|
info!("Created LDAP interface");
|
2022-11-23 11:10:43 +01:00
|
|
|
Ok(ldap_acceptor_handle)
|
2020-06-10 04:07:43 +02:00
|
|
|
}
|