comparison src/director/director-connection.c @ 22691:dca05b22217b

director: Fix crash when handling expired USER timestamps. The fix in 154f91726624265fce15097eb4bbbf6e55f8c477 wasn't complete.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Tue, 28 Nov 2017 13:10:35 +0200
parents ac58eecfb8b0
children 281472b3bb20
comparison
equal deleted inserted replaced
22690:b66965f62ae8 22691:dca05b22217b
590 return FALSE; 590 return FALSE;
591 } 591 }
592 return TRUE; 592 return TRUE;
593 } 593 }
594 594
595 static bool 595 static int
596 director_user_refresh(struct director_connection *conn, 596 director_user_refresh(struct director_connection *conn,
597 unsigned int username_hash, struct mail_host *host, 597 unsigned int username_hash, struct mail_host *host,
598 time_t timestamp, bool weak, bool *forced_r, 598 time_t timestamp, bool weak, bool *forced_r,
599 struct user **user_r) 599 struct user **user_r)
600 { 600 {
610 /* Old director version sent USER without timestamp. */ 610 /* Old director version sent USER without timestamp. */
611 timestamp = ioloop_time; 611 timestamp = ioloop_time;
612 } 612 }
613 613
614 if (timestamp + (time_t)dir->set->director_user_expire <= ioloop_time) { 614 if (timestamp + (time_t)dir->set->director_user_expire <= ioloop_time) {
615 /* Ignore this refresh entirely, regardless of whether the
616 user already exists or not. */
615 dir_debug("user refresh: %u has expired timestamp %ld", 617 dir_debug("user refresh: %u has expired timestamp %ld",
616 username_hash, (long)timestamp); 618 username_hash, (long)timestamp);
617 return TRUE; 619 return -1;
618 } 620 }
619 621
620 user = user_directory_lookup(users, username_hash); 622 user = user_directory_lookup(users, username_hash);
621 if (user == NULL) { 623 if (user == NULL) {
622 *user_r = user_directory_add(users, username_hash, 624 *user_r = user_directory_add(users, username_hash,
623 host, timestamp); 625 host, timestamp);
624 (*user_r)->weak = weak; 626 (*user_r)->weak = weak;
625 dir_debug("user refresh: %u added", username_hash); 627 dir_debug("user refresh: %u added", username_hash);
626 return TRUE; 628 return 1;
627 } 629 }
628 630
629 if (user->weak) { 631 if (user->weak) {
630 if (!weak) { 632 if (!weak) {
631 /* removing user's weakness */ 633 /* removing user's weakness */
742 this user if there are any */ 744 this user if there are any */
743 director_set_state_changed(conn->dir); 745 director_set_state_changed(conn->dir);
744 } 746 }
745 747
746 *user_r = user; 748 *user_r = user;
747 return ret; 749 return ret ? 1 : 0;
748 } 750 }
749 751
750 static bool 752 static bool
751 director_handshake_cmd_user(struct director_connection *conn, 753 director_handshake_cmd_user(struct director_connection *conn,
752 const char *const *args) 754 const char *const *args)
779 compared to us. Don't set any of our users' timestamps into 781 compared to us. Don't set any of our users' timestamps into
780 future though. It's most likely only 1 second difference. */ 782 future though. It's most likely only 1 second difference. */
781 timestamp = ioloop_time; 783 timestamp = ioloop_time;
782 } 784 }
783 conn->dir->num_incoming_requests++; 785 conn->dir->num_incoming_requests++;
784 (void)director_user_refresh(conn, username_hash, host, 786 if (director_user_refresh(conn, username_hash, host,
785 timestamp, weak, &forced, &user); 787 timestamp, weak, &forced, &user) < 0) {
788 /* user expired - ignore */
789 return TRUE;
790 }
786 /* Possibilities: 791 /* Possibilities:
787 792
788 a) The user didn't exist yet, and it was added with the given 793 a) The user didn't exist yet, and it was added with the given
789 timestamp. 794 timestamp.
790 795
834 /* we probably just removed this host. */ 839 /* we probably just removed this host. */
835 return TRUE; 840 return TRUE;
836 } 841 }
837 842
838 if (director_user_refresh(conn, username_hash, 843 if (director_user_refresh(conn, username_hash,
839 host, timestamp, FALSE, &forced, &user)) { 844 host, timestamp, FALSE, &forced, &user) > 0) {
845 /* user changed - forward the USER in the ring */
840 struct director_host *src_host = 846 struct director_host *src_host =
841 forced ? conn->dir->self_host : conn->host; 847 forced ? conn->dir->self_host : conn->host;
842 i_assert(!user->weak); 848 i_assert(!user->weak);
843 director_update_user(conn->dir, src_host, user); 849 director_update_user(conn->dir, src_host, user);
844 } 850 }
1057 dir_debug("user refresh: %u Remote USER-WEAK from %s seen by the entire ring, ignoring", 1063 dir_debug("user refresh: %u Remote USER-WEAK from %s seen by the entire ring, ignoring",
1058 username_hash, dir_host->ip_str); 1064 username_hash, dir_host->ip_str);
1059 weak_forward = TRUE; 1065 weak_forward = TRUE;
1060 } 1066 }
1061 1067
1062 if (director_user_refresh(conn, username_hash, 1068 ret = director_user_refresh(conn, username_hash,
1063 host, ioloop_time, weak, &forced, &user) || 1069 host, ioloop_time, weak, &forced, &user);
1064 weak_forward) { 1070 /* user is refreshed with ioloop_time, it can't be expired already */
1071 i_assert(ret >= 0);
1072 if (ret > 0 || weak_forward) {
1073 /* user changed, or we've decided that we need to forward
1074 the weakness notification to the rest of the ring even
1075 though we already knew it. */
1065 if (forced) 1076 if (forced)
1066 src_host = conn->dir->self_host; 1077 src_host = conn->dir->self_host;
1067 if (!user->weak) 1078 if (!user->weak)
1068 director_update_user(conn->dir, src_host, user); 1079 director_update_user(conn->dir, src_host, user);
1069 else { 1080 else {