@@ -14,7 +14,9 @@ use tokio::sync::mpsc::Sender;
14
14
15
15
use crate :: admin:: { generate_server_parameters_for_admin, handle_admin} ;
16
16
use 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
+ } ;
18
20
use crate :: constants:: * ;
19
21
use crate :: messages:: * ;
20
22
use crate :: plugins:: PluginOutput ;
@@ -463,8 +465,8 @@ where
463
465
. count ( )
464
466
== 1 ;
465
467
466
- // Kick any client that's not admin while we're in admin-only mode.
467
468
if !admin && admin_only {
469
+ // Kick any client that's not admin while we're in admin-only mode.
468
470
debug ! (
469
471
"Rejecting non-admin connection to {} when in admin only mode" ,
470
472
pool_name
@@ -481,72 +483,76 @@ where
481
483
let process_id: i32 = rand:: random ( ) ;
482
484
let secret_key: i32 = rand:: random ( ) ;
483
485
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
-
528
486
let mut prepared_statements_enabled = false ;
529
487
530
488
// Authenticate admin user.
531
489
let ( transaction_mode, mut server_parameters) = if admin {
532
490
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
+ }
533
515
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
+ } ;
540
525
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 ] ;
543
527
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
+ } ;
546
537
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) ;
549
548
549
+ warn ! ( "{}" , error) ;
550
+ wrong_password ( & mut write, username) . await ?;
551
+
552
+ return Err ( error) ;
553
+ }
554
+ }
555
+ }
550
556
( false , generate_server_parameters_for_admin ( ) )
551
557
}
552
558
// Authenticate normal user.
@@ -573,92 +579,143 @@ where
573
579
// Obtain the hash to compare, we give preference to that written in cleartext in config
574
580
// if there is nothing set in cleartext and auth passthrough (auth_query) is configured, we use the hash obtained
575
581
// 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
+ }
593
606
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
+ } ;
597
616
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 ] ;
602
618
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
+ ) )
604
626
}
627
+ } ;
605
628
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 ( ) {
607
633
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 ( ) ) ) ;
613
635
}
614
- }
615
- } ;
616
636
617
- Some ( md5_hash_second_pass ( & hash. unwrap ( ) , & salt) )
618
- } ;
637
+ let mut hash = ( * pool. auth_hash . read ( ) ) . clone ( ) ;
619
638
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
+ ) ;
630
646
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
+ ) ;
635
653
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
+ }
639
658
640
- let new_password_hash = md5_hash_second_pass ( & fetched_hash, & salt) ;
659
+ hash = Some ( fetched_hash) ;
660
+ }
641
661
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 ?;
648
664
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
+ }
652
716
}
653
- } else {
654
- wrong_password ( & mut write, username) . await ?;
655
- return Err ( Error :: ClientGeneralError (
656
- "Invalid password" . into ( ) ,
657
- client_identifier,
658
- ) ) ;
659
717
}
660
718
}
661
-
662
719
let transaction_mode = pool. settings . pool_mode == PoolMode :: Transaction ;
663
720
prepared_statements_enabled =
664
721
transaction_mode && pool. prepared_statement_cache . is_some ( ) ;
0 commit comments