Bug 20122 - Bugzilla requires new login if IP changes

r=joel x2
parent 52aac68c
...@@ -412,12 +412,31 @@ sub PasswordForLogin { ...@@ -412,12 +412,31 @@ sub PasswordForLogin {
return $result; return $result;
} }
sub get_netaddr {
my ($ipaddr) = @_;
# Check for a valid IPv4 addr which we know how to parse
if ($ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
return undef;
}
my $addr = unpack("N", pack("CCCC", split(/\./, $ipaddr)));
my $maskbits = Param('loginnetmask');
$addr >>= (32-$maskbits);
$addr <<= (32-$maskbits);
return join(".", unpack("CCCC", pack("N", $addr)));
}
sub quietly_check_login() { sub quietly_check_login() {
$::disabledreason = ''; $::disabledreason = '';
my $userid = 0; my $userid = 0;
my $ipaddr = $ENV{'REMOTE_ADDR'};
my $netaddr = get_netaddr($ipaddr);
if (defined $::COOKIE{"Bugzilla_login"} && if (defined $::COOKIE{"Bugzilla_login"} &&
defined $::COOKIE{"Bugzilla_logincookie"}) { defined $::COOKIE{"Bugzilla_logincookie"}) {
SendSQL("SELECT profiles.userid," . my $query = "SELECT profiles.userid," .
" profiles.login_name, " . " profiles.login_name, " .
" profiles.disabledtext " . " profiles.disabledtext " .
" FROM profiles, logincookies WHERE logincookies.cookie = " . " FROM profiles, logincookies WHERE logincookies.cookie = " .
...@@ -425,8 +444,14 @@ sub quietly_check_login() { ...@@ -425,8 +444,14 @@ sub quietly_check_login() {
" AND profiles.userid = logincookies.userid AND" . " AND profiles.userid = logincookies.userid AND" .
" profiles.login_name = " . " profiles.login_name = " .
SqlQuote($::COOKIE{"Bugzilla_login"}) . SqlQuote($::COOKIE{"Bugzilla_login"}) .
" AND logincookies.ipaddr = " . " AND (logincookies.ipaddr = " .
SqlQuote($ENV{"REMOTE_ADDR"})); SqlQuote($ipaddr);
if (defined $netaddr) {
$query .= " OR logincookies.ipaddr = " . SqlQuote($netaddr);
}
$query .= ")";
SendSQL($query);
my @row; my @row;
if (MoreSQLData()) { if (MoreSQLData()) {
($userid, my $loginname, my $disabledtext) = FetchSQLData(); ($userid, my $loginname, my $disabledtext) = FetchSQLData();
...@@ -728,7 +753,16 @@ sub confirm_login { ...@@ -728,7 +753,16 @@ sub confirm_login {
# the cookies. # the cookies.
if($enteredlogin ne "") { if($enteredlogin ne "") {
$::COOKIE{"Bugzilla_login"} = $enteredlogin; $::COOKIE{"Bugzilla_login"} = $enteredlogin;
SendSQL("insert into logincookies (userid,ipaddr) values (@{[DBNameToIdAndCheck($enteredlogin)]}, @{[SqlQuote($ENV{'REMOTE_ADDR'})]})"); my $ipaddr = $ENV{'REMOTE_ADDR'};
# Unless we're restricting the login, or restricting would have no
# effect, loosen the IP which we record in the table
unless ($::FORM{'Bugzilla_restrictlogin'} ||
Param('loginnetmask') == 32) {
$ipaddr = get_netaddr($ipaddr);
$ipaddr = $ENV{'REMOTE_ADDR'} unless defined $ipaddr;
}
SendSQL("insert into logincookies (userid,ipaddr) values (@{[DBNameToIdAndCheck($enteredlogin)]}, @{[SqlQuote($ipaddr)]})");
SendSQL("select LAST_INSERT_ID()"); SendSQL("select LAST_INSERT_ID()");
my $logincookie = FetchOneColumn(); my $logincookie = FetchOneColumn();
......
...@@ -111,6 +111,21 @@ sub check_webdotbase { ...@@ -111,6 +111,21 @@ sub check_webdotbase {
return ""; return "";
} }
sub check_netmask {
my ($mask) = @_;
my $res = check_numeric($mask);
return $res if $res;
if ($mask < 0 || $mask > 32) {
return "an IPv4 netmask must be between 0 and 32 bits";
}
# Note that if we changed the netmask from anything apart from 32, then
# existing logincookies which aren't for a single IP won't work
# any more. We can't know which ones they are, though, so they'll just
# take space until they're preiodically cleared, later.
return "";
}
# OK, here are the parameter definitions themselves. # OK, here are the parameter definitions themselves.
# #
# Each definition is a hash with keys: # Each definition is a hash with keys:
...@@ -845,6 +860,17 @@ Reason: %reason% ...@@ -845,6 +860,17 @@ Reason: %reason%
type => 't', type => 't',
default => '' default => ''
}, },
{
name => 'loginnetmask',
desc => 'The number of bits for the netmask used if a user chooses to ' .
'allow a login to be valid for more than a single IP. Setting ' .
'this to 32 disables this feature.<br>' .
'Note that enabling this may decrease the security of your system.',
type => 't',
default => '32',
checker => \&check_netmask
},
); );
1; 1;
......
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
<form action="[% target %]" method="POST"> <form action="[% target %]" method="POST">
<table> <table>
[% IF Param("useLDAP") %] <tr>
<tr> [% IF Param("useLDAP") %]
<td align="right"> <td align="right">
<b>Username:</b> <b>Username:</b>
</td> </td>
...@@ -54,9 +54,7 @@ ...@@ -54,9 +54,7 @@
<td> <td>
<input type="password" size="10" name="LDAP_password"> <input type="password" size="10" name="LDAP_password">
</td> </td>
</tr> [% ELSE %]
[% ELSE %]
<tr>
<td align="right"> <td align="right">
<b>E-mail address:</b> <b>E-mail address:</b>
</td> </td>
...@@ -71,8 +69,23 @@ ...@@ -71,8 +69,23 @@
<td> <td>
<input type="password" size="35" name="Bugzilla_password"> <input type="password" size="35" name="Bugzilla_password">
</td> </td>
[% END %]
[% IF Param('loginnetmask') < 32 %]
<tr>
<td align="right">
<b>
Restrict this session<br>
to this IP address:
</b>
</td>
<td>
<input type="checkbox" name="Bugzilla_restrictlogin"
checked="checked">
(Using this option increases security)
</td>
</tr> </tr>
[% END %] [% END %]
</tr>
</table> </table>
[% PROCESS "global/hidden-fields.html.tmpl" [% PROCESS "global/hidden-fields.html.tmpl"
......
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