Commit 2ea4b3d3 authored by Frédéric Buclin's avatar Frédéric Buclin

Bug 450013: (CVE-2010-2757) [SECURITY] Can sudo a user without sending email

r=glob a=LpSolit
parent 1741f7c9
...@@ -51,10 +51,12 @@ use Bugzilla::Error; ...@@ -51,10 +51,12 @@ use Bugzilla::Error;
use Bugzilla::Util; use Bugzilla::Util;
use Bugzilla::Field; use Bugzilla::Field;
use Bugzilla::Flag; use Bugzilla::Flag;
use Bugzilla::Token;
use File::Basename; use File::Basename;
use File::Spec::Functions; use File::Spec::Functions;
use DateTime::TimeZone; use DateTime::TimeZone;
use Date::Parse;
use Safe; use Safe;
##################################################################### #####################################################################
...@@ -341,24 +343,37 @@ sub login { ...@@ -341,24 +343,37 @@ sub login {
# 3: There must be a valid value in the 'sudo' cookie # 3: There must be a valid value in the 'sudo' cookie
# 4: A Bugzilla::User object must exist for the given cookie value # 4: A Bugzilla::User object must exist for the given cookie value
# 5: That user must NOT be in the 'bz_sudo_protect' group # 5: That user must NOT be in the 'bz_sudo_protect' group
my $sudo_cookie = $class->cgi->cookie('sudo'); my $token = $class->cgi->cookie('sudo');
detaint_natural($sudo_cookie) if defined($sudo_cookie); if (defined $authenticated_user && $token) {
my $sudo_target; my ($user_id, $date, $sudo_target_id) = Bugzilla::Token::GetTokenData($token);
$sudo_target = new Bugzilla::User($sudo_cookie) if defined($sudo_cookie); if (!$user_id
if (defined($authenticated_user) && || $user_id != $authenticated_user->id
$authenticated_user->in_group('bz_sudoers') && || !detaint_natural($sudo_target_id)
defined($sudo_cookie) && || (time() - str2time($date) > MAX_SUDO_TOKEN_AGE))
defined($sudo_target) && {
!($sudo_target->in_group('bz_sudo_protect')) $class->cgi->remove_cookie('sudo');
) ThrowUserError('sudo_invalid_cookie');
{ }
$class->set_user($sudo_target);
$class->request_cache->{sudoer} = $authenticated_user; my $sudo_target = new Bugzilla::User($sudo_target_id);
# And make sure that both users have the same Auth object, if ($authenticated_user->in_group('bz_sudoers')
# since we never call Auth::login for the sudo target. && defined $sudo_target
$sudo_target->set_authorizer($authenticated_user->authorizer); && !$sudo_target->in_group('bz_sudo_protect'))
{
$class->set_user($sudo_target);
$class->request_cache->{sudoer} = $authenticated_user;
# And make sure that both users have the same Auth object,
# since we never call Auth::login for the sudo target.
$sudo_target->set_authorizer($authenticated_user->authorizer);
# NOTE: If you want to do any special logging, do it here. # NOTE: If you want to do any special logging, do it here.
}
else {
delete_token($token);
$class->cgi->remove_cookie('sudo');
ThrowUserError('sudo_illegal_action', { sudoer => $authenticated_user,
target_user => $sudo_target });
}
} }
else { else {
$class->set_user($authenticated_user); $class->set_user($authenticated_user);
......
...@@ -160,6 +160,7 @@ use Memoize; ...@@ -160,6 +160,7 @@ use Memoize;
MAX_TOKEN_AGE MAX_TOKEN_AGE
MAX_LOGINCOOKIE_AGE MAX_LOGINCOOKIE_AGE
MAX_SUDO_TOKEN_AGE
MAX_LOGIN_ATTEMPTS MAX_LOGIN_ATTEMPTS
LOGIN_LOCKOUT_INTERVAL LOGIN_LOCKOUT_INTERVAL
MAX_STS_AGE MAX_STS_AGE
...@@ -415,6 +416,8 @@ use constant TIMETRACKING_FIELDS => ...@@ -415,6 +416,8 @@ use constant TIMETRACKING_FIELDS =>
use constant MAX_TOKEN_AGE => 3; use constant MAX_TOKEN_AGE => 3;
# How many days a logincookie will remain valid if not used. # How many days a logincookie will remain valid if not used.
use constant MAX_LOGINCOOKIE_AGE => 30; use constant MAX_LOGINCOOKIE_AGE => 30;
# How many seconds (default is 6 hours) a sudo cookie remains valid.
use constant MAX_SUDO_TOKEN_AGE => 21600;
# Maximum failed logins to lock account for this IP # Maximum failed logins to lock account for this IP
use constant MAX_LOGIN_ATTEMPTS => 5; use constant MAX_LOGIN_ATTEMPTS => 5;
......
...@@ -147,12 +147,13 @@ elsif ($action eq 'begin-sudo') { ...@@ -147,12 +147,13 @@ elsif ($action eq 'begin-sudo') {
$reason = substr($reason, $[, 200); $reason = substr($reason, $[, 200);
# Calculate the session expiry time (T + 6 hours) # Calculate the session expiry time (T + 6 hours)
my $time_string = time2str('%a, %d-%b-%Y %T %Z', time+(6*60*60), 'GMT'); my $time_string = time2str('%a, %d-%b-%Y %T %Z', time + MAX_SUDO_TOKEN_AGE, 'GMT');
# For future sessions, store the unique ID of the target user # For future sessions, store the unique ID of the target user
my $token = Bugzilla::Token::_create_token($user->id, 'sudo', $target_user->id);
$cgi->send_cookie('-name' => 'sudo', $cgi->send_cookie('-name' => 'sudo',
'-expires' => $time_string, '-expires' => $time_string,
'-value' => $target_user->id '-value' => $token
); );
# For the present, change the values of Bugzilla::user & Bugzilla::sudoer # For the present, change the values of Bugzilla::user & Bugzilla::sudoer
...@@ -173,6 +174,7 @@ elsif ($action eq 'begin-sudo') { ...@@ -173,6 +174,7 @@ elsif ($action eq 'begin-sudo') {
# end-sudo: End the current sudo session (if one is in progress) # end-sudo: End the current sudo session (if one is in progress)
elsif ($action eq 'end-sudo') { elsif ($action eq 'end-sudo') {
# Regardless of our state, delete the sudo cookie if it exists # Regardless of our state, delete the sudo cookie if it exists
my $token = $cgi->cookie('sudo');
$cgi->remove_cookie('sudo'); $cgi->remove_cookie('sudo');
# Are we in an sudo session? # Are we in an sudo session?
...@@ -181,6 +183,8 @@ elsif ($action eq 'end-sudo') { ...@@ -181,6 +183,8 @@ elsif ($action eq 'end-sudo') {
if (defined($sudoer)) { if (defined($sudoer)) {
Bugzilla->sudo_request($sudoer, undef); Bugzilla->sudo_request($sudoer, undef);
} }
# Now that the session is over, remove the token from the DB.
delete_token($token);
# NOTE: If you want to log the end of an sudo session, so it here. # NOTE: If you want to log the end of an sudo session, so it here.
......
...@@ -1505,6 +1505,22 @@ ...@@ -1505,6 +1505,22 @@
[% END %] [% END %]
[% END %] [% END %]
[% ELSIF error == "sudo_invalid_cookie" %]
[% title = "Invalid Sudo Cookie" %]
Your sudo cookie is invalid. Either it expired or you didn't start
a sudo session correctly. Refresh the page or load another page
to continue what you are doing as yourself.
[% ELSIF error == "sudo_illegal_action" %]
[% title = "Impersonation Not Authorized" %]
[% IF NOT sudoer.in_group("bz_sudoers") %]
You are not allowed to impersonate users.
[% ELSIF target_user AND target_user.in_group("bz_sudo_protect") %]
You are not allowed to impersonate [% target_user.identity FILTER html %].
[% ELSE %]
The user you tried to impersonate doesn't exist.
[% END %]
[% ELSIF error == "sudo_in_progress" %] [% ELSIF error == "sudo_in_progress" %]
[% title = "Session In Progress" %] [% title = "Session In Progress" %]
A sudo session (impersonating [% target FILTER html %]) is in progress. A sudo session (impersonating [% target FILTER html %]) is in progress.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment