2022-10-01 08:08:51 +02:00
use std ::marker ::Unpin ;
use std ::net ;
2022-02-20 03:43:38 +01: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
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-10-01 08:08:51 +02:00
use kanidm ::actors ::v1_read ::QueryServerReadV1 ;
use kanidm ::ldap ::{ LdapBoundToken , LdapResponseState } ;
use kanidm ::prelude ::* ;
use ldap3_proto ::proto ::LdapMsg ;
use ldap3_proto ::LdapCodec ;
use openssl ::ssl ::{ Ssl , SslAcceptor , SslAcceptorBuilder } ;
2020-09-06 00:44:35 +02:00
use tokio ::io ::{ AsyncRead , AsyncWrite } ;
use tokio ::net ::TcpListener ;
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
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
}
2020-09-06 00:44:35 +02:00
async fn client_process < W : AsyncWrite + Unpin , R : AsyncRead + Unpin > (
mut r : FramedRead < R , LdapCodec > ,
mut w : FramedWrite < W , LdapCodec > ,
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 ,
) {
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 ( ) ;
2022-02-20 03:43:38 +01:00
let caddr = client_address . clone ( ) ;
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 ,
2020-09-06 00:44:35 +02:00
tls_parms : SslAcceptor ,
qe_r_ref : & 'static QueryServerReadV1 ,
) {
loop {
match listener . accept ( ) . await {
2021-05-23 02:15:21 +02:00
Ok ( ( tcpstream , client_socket_addr ) ) = > {
// Start the event
2021-01-10 04:41:56 +01:00
// From the parms we need to create an SslContext.
let mut tlsstream = match Ssl ::new ( tls_parms . context ( ) )
. and_then ( | tls_obj | SslStream ::new ( tls_obj , tcpstream ) )
{
Ok ( ta ) = > ta ,
2020-09-06 00:44:35 +02:00
Err ( e ) = > {
2021-08-10 04:16:13 +02:00
error! ( " LDAP TLS setup error, continuing -> {:?} " , e ) ;
2020-09-06 00:44:35 +02:00
continue ;
}
} ;
2021-01-10 04:41:56 +01:00
if let Err ( e ) = SslStream ::accept ( Pin ::new ( & mut tlsstream ) ) . await {
2021-08-10 04:16:13 +02:00
error! ( " LDAP TLS accept error, continuing -> {:?} " , e ) ;
2021-01-10 04:41:56 +01:00
continue ;
} ;
2020-09-06 00:44:35 +02:00
let ( r , w ) = tokio ::io ::split ( tlsstream ) ;
let r = FramedRead ::new ( r , LdapCodec ) ;
let w = FramedWrite ::new ( w , LdapCodec ) ;
2021-05-23 02:15:21 +02:00
tokio ::spawn ( client_process ( r , w , client_socket_addr , qe_r_ref ) ) ;
2020-09-06 00:44:35 +02:00
}
Err ( e ) = > {
2021-08-10 04:16:13 +02:00
error! ( " LDAP acceptor error, continuing -> {:?} " , e ) ;
2020-06-10 04:07:43 +02:00
}
}
}
}
2021-08-10 04:16:13 +02:00
/// Plain TCP LDAP Listener, hands off to [client_process]
2022-09-21 05:36:58 +02:00
// async fn acceptor(listener: TcpListener, qe_r_ref: &'static QueryServerReadV1) {
// loop {
// match listener.accept().await {
// Ok((tcpstream, client_socket_addr)) => {
// // Start the event
// let (r, w) = tokio::io::split(tcpstream);
// let r = FramedRead::new(r, LdapCodec);
// let w = FramedWrite::new(w, LdapCodec);
// // Let it rip.
// tokio::spawn(client_process(r, w, client_socket_addr, qe_r_ref));
// }
// Err(e) => {
// error!("LDAP acceptor error, continuing -> {:?}", e);
// }
// }
// }
// }
2020-06-10 04:07:43 +02:00
pub ( crate ) async fn create_ldap_server (
address : & str ,
opt_tls_params : Option < SslAcceptorBuilder > ,
2020-09-06 00:44:35 +02:00
qe_r_ref : & 'static QueryServerReadV1 ,
2020-06-10 04:07:43 +02:00
) -> Result < ( ) , ( ) > {
2021-04-26 03:52:13 +02:00
if address . starts_with ( " ::: " ) {
// takes :::xxxx to xxxx
let port = address . replacen ( " ::: " , " " , 1 ) ;
eprintln! ( " Address ' {} ' looks like an attempt to wildcard bind with IPv6 on port {} - please try using ldapbindaddress = '[::]: {} ' " , address , port , port ) ;
} ;
2020-06-10 04:07:43 +02:00
let addr = net ::SocketAddr ::from_str ( address ) . map_err ( | e | {
2022-09-21 05:36:58 +02:00
eprintln! ( " 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 | {
2020-08-04 04:58:11 +02:00
eprintln! (
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
match opt_tls_params {
Some ( tls_params ) = > {
2021-08-10 04:16:13 +02:00
eprintln! ( " Starting LDAPS interface ldaps:// {} ... " , address ) ;
2020-09-06 00:44:35 +02:00
let tls_parms = tls_params . build ( ) ;
tokio ::spawn ( tls_acceptor ( listener , tls_parms , qe_r_ref ) ) ;
2020-06-10 04:07:43 +02:00
}
None = > {
2022-09-21 05:36:58 +02:00
eprintln! ( " The server won't run without TLS! " ) ;
return Err ( ( ) ) ;
2020-06-10 04:07:43 +02:00
}
}
info! ( " Created LDAP interface " ) ;
Ok ( ( ) )
}