2021-05-09 14:06:04 +02:00
use crate ::actors ::v1_read ::QueryServerReadV1 ;
2020-06-10 04:07:43 +02:00
use crate ::ldap ::{ LdapBoundToken , LdapResponseState } ;
2021-09-21 04:42:00 +02:00
use crate ::prelude ::* ;
2021-01-10 04:41:56 +01:00
use core ::pin ::Pin ;
use openssl ::ssl ::{ Ssl , SslAcceptor , SslAcceptorBuilder } ;
use tokio_openssl ::SslStream ;
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 ;
use ldap3_server ::LdapCodec ;
use std ::marker ::Unpin ;
use std ::net ;
use std ::str ::FromStr ;
2020-09-06 00:44:35 +02:00
use tokio ::io ::{ AsyncRead , AsyncWrite } ;
use tokio ::net ::TcpListener ;
use tokio_util ::codec ::{ FramedRead , FramedWrite } ;
2020-06-10 04:07:43 +02:00
use uuid ::Uuid ;
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
}
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
2020-06-10 04:07:43 +02:00
let eventid = Uuid ::new_v4 ( ) ;
2020-09-06 00:44:35 +02:00
let uat = session . uat . clone ( ) ;
2021-08-10 04:16:13 +02:00
// 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.
2021-09-21 04:42:00 +02:00
security_info! (
client_ip = % client_address . ip ( ) ,
client_port = % client_address . port ( ) ,
" LDAP client "
2021-08-10 04:16:13 +02:00
) ;
2021-09-21 04:42:00 +02:00
let qs_result = qe_r_ref . handle_ldaprequest ( eventid , protomsg , uat ) . await ;
2020-09-06 00:44:35 +02:00
match qs_result {
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]
2021-01-10 04:41:56 +01:00
async fn acceptor ( listener : TcpListener , qe_r_ref : & 'static QueryServerReadV1 ) {
2020-09-06 00:44:35 +02:00
loop {
match listener . accept ( ) . await {
2021-05-23 02:15:21 +02:00
Ok ( ( tcpstream , client_socket_addr ) ) = > {
// Start the event
2020-09-06 00:44:35 +02:00
let ( r , w ) = tokio ::io ::split ( tcpstream ) ;
let r = FramedRead ::new ( r , LdapCodec ) ;
let w = FramedWrite ::new ( w , LdapCodec ) ;
// Let it rip.
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-09-06 00:44:35 +02:00
}
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 | {
2020-06-18 02:30:42 +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! (
" Could not bind to ldap server address {} -> {:?} " ,
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 = > {
2021-08-10 04:16:13 +02:00
eprintln! ( " Starting LDAP interface ldap:// {} ... " , address ) ;
2020-09-06 00:44:35 +02:00
tokio ::spawn ( acceptor ( listener , qe_r_ref ) ) ;
2020-06-10 04:07:43 +02:00
}
}
info! ( " Created LDAP interface " ) ;
Ok ( ( ) )
}