@@ -14,7 +14,9 @@ use tokio::sync::mpsc::Sender;
1414
1515use crate :: admin:: { generate_server_parameters_for_admin, handle_admin} ;
1616use crate :: auth_passthrough:: refetch_auth_hash;
17- use crate :: config:: { get_config, get_idle_client_in_transaction_timeout, Address , PoolMode } ;
17+ use crate :: config:: {
18+ get_config, get_idle_client_in_transaction_timeout, Address , AuthType , PoolMode ,
19+ } ;
1820use crate :: constants:: * ;
1921use crate :: messages:: * ;
2022use crate :: plugins:: PluginOutput ;
@@ -463,8 +465,8 @@ where
463465 . count ( )
464466 == 1 ;
465467
466- // Kick any client that's not admin while we're in admin-only mode.
467468 if !admin && admin_only {
469+ // Kick any client that's not admin while we're in admin-only mode.
468470 debug ! (
469471 "Rejecting non-admin connection to {} when in admin only mode" ,
470472 pool_name
@@ -481,72 +483,76 @@ where
481483 let process_id: i32 = rand:: random ( ) ;
482484 let secret_key: i32 = rand:: random ( ) ;
483485
484- // Perform MD5 authentication.
485- // TODO: Add SASL support.
486- let salt = md5_challenge ( & mut write) . await ?;
487-
488- let code = match read. read_u8 ( ) . await {
489- Ok ( p) => p,
490- Err ( _) => {
491- return Err ( Error :: ClientSocketError (
492- "password code" . into ( ) ,
493- client_identifier,
494- ) )
495- }
496- } ;
497-
498- // PasswordMessage
499- if code as char != 'p' {
500- return Err ( Error :: ProtocolSyncError ( format ! (
501- "Expected p, got {}" ,
502- code as char
503- ) ) ) ;
504- }
505-
506- let len = match read. read_i32 ( ) . await {
507- Ok ( len) => len,
508- Err ( _) => {
509- return Err ( Error :: ClientSocketError (
510- "password message length" . into ( ) ,
511- client_identifier,
512- ) )
513- }
514- } ;
515-
516- let mut password_response = vec ! [ 0u8 ; ( len - 4 ) as usize ] ;
517-
518- match read. read_exact ( & mut password_response) . await {
519- Ok ( _) => ( ) ,
520- Err ( _) => {
521- return Err ( Error :: ClientSocketError (
522- "password message" . into ( ) ,
523- client_identifier,
524- ) )
525- }
526- } ;
527-
528486 let mut prepared_statements_enabled = false ;
529487
530488 // Authenticate admin user.
531489 let ( transaction_mode, mut server_parameters) = if admin {
532490 let config = get_config ( ) ;
491+ // TODO: Add SASL support.
492+ // Perform MD5 authentication.
493+ match config. general . admin_auth_type {
494+ AuthType :: Trust => ( ) ,
495+ AuthType :: MD5 => {
496+ let salt = md5_challenge ( & mut write) . await ?;
497+
498+ let code = match read. read_u8 ( ) . await {
499+ Ok ( p) => p,
500+ Err ( _) => {
501+ return Err ( Error :: ClientSocketError (
502+ "password code" . into ( ) ,
503+ client_identifier,
504+ ) )
505+ }
506+ } ;
507+
508+ // PasswordMessage
509+ if code as char != 'p' {
510+ return Err ( Error :: ProtocolSyncError ( format ! (
511+ "Expected p, got {}" ,
512+ code as char
513+ ) ) ) ;
514+ }
533515
534- // Compare server and client hashes.
535- let password_hash = md5_hash_password (
536- & config. general . admin_username ,
537- & config. general . admin_password ,
538- & salt,
539- ) ;
516+ let len = match read. read_i32 ( ) . await {
517+ Ok ( len) => len,
518+ Err ( _) => {
519+ return Err ( Error :: ClientSocketError (
520+ "password message length" . into ( ) ,
521+ client_identifier,
522+ ) )
523+ }
524+ } ;
540525
541- if password_hash != password_response {
542- let error = Error :: ClientGeneralError ( "Invalid password" . into ( ) , client_identifier) ;
526+ let mut password_response = vec ! [ 0u8 ; ( len - 4 ) as usize ] ;
543527
544- warn ! ( "{}" , error) ;
545- wrong_password ( & mut write, username) . await ?;
528+ match read. read_exact ( & mut password_response) . await {
529+ Ok ( _) => ( ) ,
530+ Err ( _) => {
531+ return Err ( Error :: ClientSocketError (
532+ "password message" . into ( ) ,
533+ client_identifier,
534+ ) )
535+ }
536+ } ;
546537
547- return Err ( error) ;
548- }
538+ // Compare server and client hashes.
539+ let password_hash = md5_hash_password (
540+ & config. general . admin_username ,
541+ & config. general . admin_password ,
542+ & salt,
543+ ) ;
544+
545+ if password_hash != password_response {
546+ let error =
547+ Error :: ClientGeneralError ( "Invalid password" . into ( ) , client_identifier) ;
549548
549+ warn ! ( "{}" , error) ;
550+ wrong_password ( & mut write, username) . await ?;
551+
552+ return Err ( error) ;
553+ }
554+ }
555+ }
550556 ( false , generate_server_parameters_for_admin ( ) )
551557 }
552558 // Authenticate normal user.
@@ -573,92 +579,143 @@ where
573579 // Obtain the hash to compare, we give preference to that written in cleartext in config
574580 // if there is nothing set in cleartext and auth passthrough (auth_query) is configured, we use the hash obtained
575581 // when the pool was created. If there is no hash there, we try to fetch it one more time.
576- let password_hash = if let Some ( password) = & pool. settings . user . password {
577- Some ( md5_hash_password ( username, password, & salt) )
578- } else {
579- if !get_config ( ) . is_auth_query_configured ( ) {
580- wrong_password ( & mut write, username) . await ?;
581- return Err ( Error :: ClientAuthImpossible ( username. into ( ) ) ) ;
582- }
583-
584- let mut hash = ( * pool. auth_hash . read ( ) ) . clone ( ) ;
585-
586- if hash. is_none ( ) {
587- warn ! (
588- "Query auth configured \
589- but no hash password found \
590- for pool {}. Will try to refetch it.",
591- pool_name
592- ) ;
582+ match pool. settings . user . auth_type {
583+ AuthType :: Trust => ( ) ,
584+ AuthType :: MD5 => {
585+ // Perform MD5 authentication.
586+ // TODO: Add SASL support.
587+ let salt = md5_challenge ( & mut write) . await ?;
588+
589+ let code = match read. read_u8 ( ) . await {
590+ Ok ( p) => p,
591+ Err ( _) => {
592+ return Err ( Error :: ClientSocketError (
593+ "password code" . into ( ) ,
594+ client_identifier,
595+ ) )
596+ }
597+ } ;
598+
599+ // PasswordMessage
600+ if code as char != 'p' {
601+ return Err ( Error :: ProtocolSyncError ( format ! (
602+ "Expected p, got {}" ,
603+ code as char
604+ ) ) ) ;
605+ }
593606
594- match refetch_auth_hash ( & pool) . await {
595- Ok ( fetched_hash) => {
596- warn ! ( "Password for {}, obtained. Updating." , client_identifier) ;
607+ let len = match read. read_i32 ( ) . await {
608+ Ok ( len) => len,
609+ Err ( _) => {
610+ return Err ( Error :: ClientSocketError (
611+ "password message length" . into ( ) ,
612+ client_identifier,
613+ ) )
614+ }
615+ } ;
597616
598- {
599- let mut pool_auth_hash = pool. auth_hash . write ( ) ;
600- * pool_auth_hash = Some ( fetched_hash. clone ( ) ) ;
601- }
617+ let mut password_response = vec ! [ 0u8 ; ( len - 4 ) as usize ] ;
602618
603- hash = Some ( fetched_hash) ;
619+ match read. read_exact ( & mut password_response) . await {
620+ Ok ( _) => ( ) ,
621+ Err ( _) => {
622+ return Err ( Error :: ClientSocketError (
623+ "password message" . into ( ) ,
624+ client_identifier,
625+ ) )
604626 }
627+ } ;
605628
606- Err ( err) => {
629+ let password_hash = if let Some ( password) = & pool. settings . user . password {
630+ Some ( md5_hash_password ( username, password, & salt) )
631+ } else {
632+ if !get_config ( ) . is_auth_query_configured ( ) {
607633 wrong_password ( & mut write, username) . await ?;
608-
609- return Err ( Error :: ClientAuthPassthroughError (
610- err. to_string ( ) ,
611- client_identifier,
612- ) ) ;
634+ return Err ( Error :: ClientAuthImpossible ( username. into ( ) ) ) ;
613635 }
614- }
615- } ;
616636
617- Some ( md5_hash_second_pass ( & hash. unwrap ( ) , & salt) )
618- } ;
637+ let mut hash = ( * pool. auth_hash . read ( ) ) . clone ( ) ;
619638
620- // Once we have the resulting hash, we compare with what the client gave us.
621- // If they do not match and auth query is set up, we try to refetch the hash one more time
622- // to see if the password has changed since the pool was created.
623- //
624- // @TODO: we could end up fetching again the same password twice (see above).
625- if password_hash. unwrap ( ) != password_response {
626- warn ! (
627- "Invalid password {}, will try to refetch it." ,
628- client_identifier
629- ) ;
639+ if hash. is_none ( ) {
640+ warn ! (
641+ "Query auth configured \
642+ but no hash password found \
643+ for pool {}. Will try to refetch it.",
644+ pool_name
645+ ) ;
630646
631- let fetched_hash = match refetch_auth_hash ( & pool) . await {
632- Ok ( fetched_hash) => fetched_hash,
633- Err ( err) => {
634- wrong_password ( & mut write, username) . await ?;
647+ match refetch_auth_hash ( & pool) . await {
648+ Ok ( fetched_hash) => {
649+ warn ! (
650+ "Password for {}, obtained. Updating." ,
651+ client_identifier
652+ ) ;
635653
636- return Err ( err) ;
637- }
638- } ;
654+ {
655+ let mut pool_auth_hash = pool. auth_hash . write ( ) ;
656+ * pool_auth_hash = Some ( fetched_hash. clone ( ) ) ;
657+ }
639658
640- let new_password_hash = md5_hash_second_pass ( & fetched_hash, & salt) ;
659+ hash = Some ( fetched_hash) ;
660+ }
641661
642- // Ok password changed in server an auth is possible.
643- if new_password_hash == password_response {
644- warn ! (
645- "Password for {}, changed in server. Updating." ,
646- client_identifier
647- ) ;
662+ Err ( err) => {
663+ wrong_password ( & mut write, username) . await ?;
648664
649- {
650- let mut pool_auth_hash = pool. auth_hash . write ( ) ;
651- * pool_auth_hash = Some ( fetched_hash) ;
665+ return Err ( Error :: ClientAuthPassthroughError (
666+ err. to_string ( ) ,
667+ client_identifier,
668+ ) ) ;
669+ }
670+ }
671+ } ;
672+
673+ Some ( md5_hash_second_pass ( & hash. unwrap ( ) , & salt) )
674+ } ;
675+
676+ // Once we have the resulting hash, we compare with what the client gave us.
677+ // If they do not match and auth query is set up, we try to refetch the hash one more time
678+ // to see if the password has changed since the pool was created.
679+ //
680+ // @TODO: we could end up fetching again the same password twice (see above).
681+ if password_hash. unwrap ( ) != password_response {
682+ warn ! (
683+ "Invalid password {}, will try to refetch it." ,
684+ client_identifier
685+ ) ;
686+
687+ let fetched_hash = match refetch_auth_hash ( & pool) . await {
688+ Ok ( fetched_hash) => fetched_hash,
689+ Err ( err) => {
690+ wrong_password ( & mut write, username) . await ?;
691+
692+ return Err ( err) ;
693+ }
694+ } ;
695+
696+ let new_password_hash = md5_hash_second_pass ( & fetched_hash, & salt) ;
697+
698+ // Ok password changed in server an auth is possible.
699+ if new_password_hash == password_response {
700+ warn ! (
701+ "Password for {}, changed in server. Updating." ,
702+ client_identifier
703+ ) ;
704+
705+ {
706+ let mut pool_auth_hash = pool. auth_hash . write ( ) ;
707+ * pool_auth_hash = Some ( fetched_hash) ;
708+ }
709+ } else {
710+ wrong_password ( & mut write, username) . await ?;
711+ return Err ( Error :: ClientGeneralError (
712+ "Invalid password" . into ( ) ,
713+ client_identifier,
714+ ) ) ;
715+ }
652716 }
653- } else {
654- wrong_password ( & mut write, username) . await ?;
655- return Err ( Error :: ClientGeneralError (
656- "Invalid password" . into ( ) ,
657- client_identifier,
658- ) ) ;
659717 }
660718 }
661-
662719 let transaction_mode = pool. settings . pool_mode == PoolMode :: Transaction ;
663720 prepared_statements_enabled =
664721 transaction_mode && pool. prepared_statement_cache . is_some ( ) ;
0 commit comments