summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/Token.pm118
-rw-r--r--CGI.pl6
-rw-r--r--Token.pm118
-rwxr-xr-xcreateaccount.cgi2
-rw-r--r--defparams.pl6
-rwxr-xr-xeditusers.cgi2
-rw-r--r--globals.pl37
-rwxr-xr-xtoken.cgi129
-rwxr-xr-xuserprefs.cgi95
9 files changed, 451 insertions, 62 deletions
diff --git a/Bugzilla/Token.pm b/Bugzilla/Token.pm
index 4f7f61882..9c136184b 100644
--- a/Bugzilla/Token.pm
+++ b/Bugzilla/Token.pm
@@ -37,6 +37,62 @@ package Token;
# Functions
################################################################################
+sub IssueEmailChangeToken {
+ my ($userid, $old_email, $new_email) = @_;
+
+ # Generate a unique token and insert it into the tokens table.
+ # We have to lock the tokens table before generating the token,
+ # since the database must be queried for token uniqueness.
+ &::SendSQL("LOCK TABLES tokens WRITE");
+ my $token = GenerateUniqueToken();
+ my $quotedtoken = &::SqlQuote($token);
+ my $quoted_emails = &::SqlQuote($old_email . ":" . $new_email);
+ &::SendSQL("INSERT INTO tokens ( userid , issuedate , token ,
+ tokentype , eventdata )
+ VALUES ( $userid , NOW() , $quotedtoken ,
+ 'emailold' , $quoted_emails )");
+ my $newtoken = GenerateUniqueToken();
+ $quotedtoken = &::SqlQuote($newtoken);
+ &::SendSQL("INSERT INTO tokens ( userid , issuedate , token ,
+ tokentype , eventdata )
+ VALUES ( $userid , NOW() , $quotedtoken ,
+ 'emailnew' , $quoted_emails )");
+ &::SendSQL("UNLOCK TABLES");
+
+ # Mail the user the token along with instructions for using it.
+
+ my $template = $::template;
+ my $vars = $::vars;
+
+ $vars->{'oldemailaddress'} = $old_email . &::Param('emailsuffix');
+ $vars->{'newemailaddress'} = $new_email . &::Param('emailsuffix');
+
+ $vars->{'token'} = &::url_quote($token);
+ $vars->{'emailaddress'} = $old_email . &::Param('emailsuffix');
+
+ my $message;
+ $template->process("token/emailchangeold.txt.tmpl", $vars, \$message)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+
+ open SENDMAIL, "|/usr/lib/sendmail -t -i";
+ print SENDMAIL $message;
+ close SENDMAIL;
+
+ $vars->{'token'} = &::url_quote($newtoken);
+ $vars->{'emailaddress'} = $new_email . &::Param('emailsuffix');
+
+ $message = "";
+ $template->process("token/emailchangenew.txt.tmpl", $vars, \$message)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+
+ open SENDMAIL, "|/usr/lib/sendmail -t -i";
+ print SENDMAIL $message;
+ close SENDMAIL;
+
+}
+
sub IssuePasswordToken {
# Generates a random token, adds it to the tokens table, and sends it
# to the user with instructions for using it to change their password.
@@ -65,6 +121,14 @@ sub IssuePasswordToken {
}
+sub CleanTokenTable {
+ &::SendSQL("LOCK TABLES tokens WRITE");
+ &::SendSQL("DELETE FROM tokens
+ WHERE TO_DAYS(NOW()) - TO_DAYS(issuedate) >= 3");
+ &::SendSQL("UNLOCK TABLES");
+}
+
+
sub GenerateUniqueToken {
# Generates a unique random token. Uses &GenerateRandomPassword
# for the tokens themselves and checks uniqueness by searching for
@@ -143,25 +207,27 @@ sub Cancel {
# Format the user's real name and email address into a single string.
my $username = $realname ? $realname . " <" . $loginname . ">" : $loginname;
- # Notify the user via email about the cancellation.
- open SENDMAIL, "|/usr/lib/sendmail -t -i";
- print SENDMAIL qq|From: bugzilla-daemon
-To: $username
-Subject: "$tokentype" token cancelled
+ my $template = $::template;
+ my $vars = $::vars;
-A token was cancelled from $::ENV{'REMOTE_ADDR'}. This is either
-an honest mistake or the result of a malicious hack attempt.
-Take a look at the information below and forward this email
-to $maintainer if you suspect foul play.
+ $vars->{'emailaddress'} = $username;
+ $vars->{'maintainer'} = $maintainer;
+ $vars->{'remoteaddress'} = $::ENV{'REMOTE_ADDR'};
+ $vars->{'token'} = &::url_quote($token);
+ $vars->{'tokentype'} = $tokentype;
+ $vars->{'issuedate'} = $issuedate;
+ $vars->{'eventdata'} = $eventdata;
+ $vars->{'cancelaction'} = $cancelaction;
- Token: $token
- Token Type: $tokentype
- User: $username
- Issue Date: $issuedate
- Event Data: $eventdata
+ # Notify the user via email about the cancellation.
-Cancelled Because: $cancelaction
-|;
+ my $message;
+ $template->process("token/tokencancel.txt.tmpl", $vars, \$message)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+
+ open SENDMAIL, "|/usr/lib/sendmail -t -i";
+ print SENDMAIL $message;
close SENDMAIL;
# Delete the token from the database.
@@ -171,14 +237,30 @@ Cancelled Because: $cancelaction
}
sub HasPasswordToken {
- # Returns a password token if the user has one. Otherwise returns 0 (false).
+ # Returns a password token if the user has one.
my ($userid) = @_;
- &::SendSQL("SELECT token FROM tokens WHERE userid = $userid LIMIT 1");
+ &::SendSQL("SELECT token FROM tokens
+ WHERE userid = $userid AND tokentype = 'password' LIMIT 1");
my ($token) = &::FetchSQLData();
return $token;
}
+sub HasEmailChangeToken {
+ # Returns an email change token if the user has one.
+
+ my ($userid) = @_;
+
+ &::SendSQL("SELECT token FROM tokens
+ WHERE userid = $userid
+ AND tokentype = 'emailnew'
+ OR tokentype = 'emailold' LIMIT 1");
+ my ($token) = &::FetchSQLData();
+
+ return $token;
+}
+
+
1;
diff --git a/CGI.pl b/CGI.pl
index 2b8f5d048..be6c95270 100644
--- a/CGI.pl
+++ b/CGI.pl
@@ -814,6 +814,12 @@ sub confirm_login {
# If this is a new user, generate a password, insert a record
# into the database, and email their password to them.
if ( defined $::FORM{"PleaseMailAPassword"} && !$userid ) {
+ # Ensure the new login is valid
+ if(!ValidateNewUser($enteredlogin)) {
+ DisplayError("Account Exists");
+ exit;
+ }
+
my $password = InsertNewUser($enteredlogin, "");
# There's a template for this - account_created.tmpl - but
# it's easier to wait to use it until templatisation has progressed
diff --git a/Token.pm b/Token.pm
index 4f7f61882..9c136184b 100644
--- a/Token.pm
+++ b/Token.pm
@@ -37,6 +37,62 @@ package Token;
# Functions
################################################################################
+sub IssueEmailChangeToken {
+ my ($userid, $old_email, $new_email) = @_;
+
+ # Generate a unique token and insert it into the tokens table.
+ # We have to lock the tokens table before generating the token,
+ # since the database must be queried for token uniqueness.
+ &::SendSQL("LOCK TABLES tokens WRITE");
+ my $token = GenerateUniqueToken();
+ my $quotedtoken = &::SqlQuote($token);
+ my $quoted_emails = &::SqlQuote($old_email . ":" . $new_email);
+ &::SendSQL("INSERT INTO tokens ( userid , issuedate , token ,
+ tokentype , eventdata )
+ VALUES ( $userid , NOW() , $quotedtoken ,
+ 'emailold' , $quoted_emails )");
+ my $newtoken = GenerateUniqueToken();
+ $quotedtoken = &::SqlQuote($newtoken);
+ &::SendSQL("INSERT INTO tokens ( userid , issuedate , token ,
+ tokentype , eventdata )
+ VALUES ( $userid , NOW() , $quotedtoken ,
+ 'emailnew' , $quoted_emails )");
+ &::SendSQL("UNLOCK TABLES");
+
+ # Mail the user the token along with instructions for using it.
+
+ my $template = $::template;
+ my $vars = $::vars;
+
+ $vars->{'oldemailaddress'} = $old_email . &::Param('emailsuffix');
+ $vars->{'newemailaddress'} = $new_email . &::Param('emailsuffix');
+
+ $vars->{'token'} = &::url_quote($token);
+ $vars->{'emailaddress'} = $old_email . &::Param('emailsuffix');
+
+ my $message;
+ $template->process("token/emailchangeold.txt.tmpl", $vars, \$message)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+
+ open SENDMAIL, "|/usr/lib/sendmail -t -i";
+ print SENDMAIL $message;
+ close SENDMAIL;
+
+ $vars->{'token'} = &::url_quote($newtoken);
+ $vars->{'emailaddress'} = $new_email . &::Param('emailsuffix');
+
+ $message = "";
+ $template->process("token/emailchangenew.txt.tmpl", $vars, \$message)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+
+ open SENDMAIL, "|/usr/lib/sendmail -t -i";
+ print SENDMAIL $message;
+ close SENDMAIL;
+
+}
+
sub IssuePasswordToken {
# Generates a random token, adds it to the tokens table, and sends it
# to the user with instructions for using it to change their password.
@@ -65,6 +121,14 @@ sub IssuePasswordToken {
}
+sub CleanTokenTable {
+ &::SendSQL("LOCK TABLES tokens WRITE");
+ &::SendSQL("DELETE FROM tokens
+ WHERE TO_DAYS(NOW()) - TO_DAYS(issuedate) >= 3");
+ &::SendSQL("UNLOCK TABLES");
+}
+
+
sub GenerateUniqueToken {
# Generates a unique random token. Uses &GenerateRandomPassword
# for the tokens themselves and checks uniqueness by searching for
@@ -143,25 +207,27 @@ sub Cancel {
# Format the user's real name and email address into a single string.
my $username = $realname ? $realname . " <" . $loginname . ">" : $loginname;
- # Notify the user via email about the cancellation.
- open SENDMAIL, "|/usr/lib/sendmail -t -i";
- print SENDMAIL qq|From: bugzilla-daemon
-To: $username
-Subject: "$tokentype" token cancelled
+ my $template = $::template;
+ my $vars = $::vars;
-A token was cancelled from $::ENV{'REMOTE_ADDR'}. This is either
-an honest mistake or the result of a malicious hack attempt.
-Take a look at the information below and forward this email
-to $maintainer if you suspect foul play.
+ $vars->{'emailaddress'} = $username;
+ $vars->{'maintainer'} = $maintainer;
+ $vars->{'remoteaddress'} = $::ENV{'REMOTE_ADDR'};
+ $vars->{'token'} = &::url_quote($token);
+ $vars->{'tokentype'} = $tokentype;
+ $vars->{'issuedate'} = $issuedate;
+ $vars->{'eventdata'} = $eventdata;
+ $vars->{'cancelaction'} = $cancelaction;
- Token: $token
- Token Type: $tokentype
- User: $username
- Issue Date: $issuedate
- Event Data: $eventdata
+ # Notify the user via email about the cancellation.
-Cancelled Because: $cancelaction
-|;
+ my $message;
+ $template->process("token/tokencancel.txt.tmpl", $vars, \$message)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+
+ open SENDMAIL, "|/usr/lib/sendmail -t -i";
+ print SENDMAIL $message;
close SENDMAIL;
# Delete the token from the database.
@@ -171,14 +237,30 @@ Cancelled Because: $cancelaction
}
sub HasPasswordToken {
- # Returns a password token if the user has one. Otherwise returns 0 (false).
+ # Returns a password token if the user has one.
my ($userid) = @_;
- &::SendSQL("SELECT token FROM tokens WHERE userid = $userid LIMIT 1");
+ &::SendSQL("SELECT token FROM tokens
+ WHERE userid = $userid AND tokentype = 'password' LIMIT 1");
my ($token) = &::FetchSQLData();
return $token;
}
+sub HasEmailChangeToken {
+ # Returns an email change token if the user has one.
+
+ my ($userid) = @_;
+
+ &::SendSQL("SELECT token FROM tokens
+ WHERE userid = $userid
+ AND tokentype = 'emailnew'
+ OR tokentype = 'emailold' LIMIT 1");
+ my ($token) = &::FetchSQLData();
+
+ return $token;
+}
+
+
1;
diff --git a/createaccount.cgi b/createaccount.cgi
index ecf3a68f6..aaec3b679 100755
--- a/createaccount.cgi
+++ b/createaccount.cgi
@@ -65,7 +65,7 @@ if (defined($login)) {
CheckEmailSyntax($login);
$vars->{'login'} = $login;
- if (DBname_to_id($login) != 0) {
+ if (!ValidateNewUser($login)) {
# Account already exists
$template->process("admin/account_exists.tmpl", $vars)
|| DisplayError("Template process failed: " . $template->error());
diff --git a/defparams.pl b/defparams.pl
index 7fc73f51b..f5b7ba098 100644
--- a/defparams.pl
+++ b/defparams.pl
@@ -625,6 +625,12 @@ DefParam("allowbugdeletion",
0);
+DefParam("allowemailchange",
+ q{Users can change their own email address through the preferences. Note that the change is validated by emailing both addresses, so switching this option on will not let users use an invalid address.},
+ "b",
+ 0);
+
+
DefParam("allowuserdeletion",
q{The pages to edit users can also let you delete a user. But there is no code that goes and cleans up any references to that user in other tables, so such deletions are kinda scary. So, you have to turn on this option before any such deletions will ever happen.},
"b",
diff --git a/editusers.cgi b/editusers.cgi
index bc864bcf0..3c2409155 100755
--- a/editusers.cgi
+++ b/editusers.cgi
@@ -451,7 +451,7 @@ if ($action eq 'new') {
PutTrailer($localtrailer);
exit;
}
- if (TestUser($user)) {
+ if (!ValidateNewUser($user)) {
print "The user '$user' does already exist. Please press\n";
print "<b>Back</b> and try again.\n";
PutTrailer($localtrailer);
diff --git a/globals.pl b/globals.pl
index 562237a68..cb3612671 100644
--- a/globals.pl
+++ b/globals.pl
@@ -671,6 +671,8 @@ sub GetVersionTable {
$mtime = 0;
}
if (time() - $mtime > 3600) {
+ use Token;
+ Token::CleanTokenTable();
GenerateVersionTable();
}
require 'data/versioncache';
@@ -686,6 +688,31 @@ sub GetVersionTable {
}
+# Validates a given username as a new username
+# returns 1 if valid, 0 if invalid
+sub ValidateNewUser {
+ my ($username, $old_username) = @_;
+
+ if(DBname_to_id($username) != 0) {
+ return 0;
+ }
+
+ # Reject if the new login is part of an email change which is
+ # still in progress
+ SendSQL("SELECT eventdata FROM tokens WHERE tokentype = 'emailold'
+ AND eventdata like '%:$username'
+ OR eventdata like '$username:%'");
+ if (my ($eventdata) = FetchSQLData()) {
+ # Allow thru owner of token
+ if($old_username && ($eventdata eq "$old_username:$username")) {
+ return 1;
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
sub InsertNewUser {
my ($username, $realname) = (@_);
@@ -963,10 +990,12 @@ sub DBNameToIdAndCheck {
return $result;
}
if ($forceok) {
- InsertNewUser($name, "");
- $result = DBname_to_id($name);
- if ($result > 0) {
- return $result;
+ if(ValidateNewUser($name)) {
+ InsertNewUser($name, "");
+ $result = DBname_to_id($name);
+ if ($result > 0) {
+ return $result;
+ }
}
print "Yikes; couldn't create user $name. Please report problem to " .
Param("maintainer") ."\n";
diff --git a/token.cgi b/token.cgi
index d0de17baa..e8fb3f90f 100755
--- a/token.cgi
+++ b/token.cgi
@@ -69,10 +69,13 @@ if ($::FORM{'t'}) {
exit;
}
+
+ Token::CleanTokenTable();
+
# Make sure the token exists in the database.
SendSQL( "SELECT tokentype FROM tokens WHERE token = $::quotedtoken" );
(my $tokentype = FetchSQLData())
- || DisplayError("The token you submitted does not exist.")
+ || DisplayError("The token you submitted does not exist, has expired, or has been cancelled.")
&& exit;
# Make sure the token is the correct type for the action being taken.
@@ -81,6 +84,20 @@ if ($::FORM{'t'}) {
Token::Cancel($::token, "user tried to use token to change password");
exit;
}
+ if ( ($::action eq 'cxlem')
+ && (($tokentype ne 'emailold') && ($tokentype ne 'emailnew')) ) {
+ DisplayError("That token cannot be used to cancel an email address change.");
+ Token::Cancel($::token,
+ "user tried to use token to cancel email address change");
+ exit;
+ }
+ if ( grep($::action eq $_ , qw(cfmem chgem))
+ && ($tokentype ne 'emailnew') ) {
+ DisplayError("That token cannot be used to change your email address.");
+ Token::Cancel($::token,
+ "user tried to use token to confirm email address change");
+ exit;
+ }
}
# If the user is requesting a password change, make sure they submitted
@@ -132,6 +149,12 @@ if ($::action eq 'reqpw') {
cancelChangePassword();
} elsif ($::action eq 'chgpw') {
changePassword();
+} elsif ($::action eq 'cfmem') {
+ confirmChangeEmail();
+} elsif ($::action eq 'cxlem') {
+ cancelChangeEmail();
+} elsif ($::action eq 'chgem') {
+ changeEmail();
} else {
# If the action that the user wants to take (specified in the "a" form field)
# is none of the above listed actions, display an error telling the user
@@ -210,6 +233,110 @@ sub changePassword {
&& exit;
}
+sub confirmChangeEmail {
+ # Return HTTP response headers.
+ print "Content-Type: text/html\n\n";
+
+ $vars->{'title'} = "Confirm Change Email";
+ $vars->{'token'} = $::token;
+
+ $template->process("token/confirmemail.html.tmpl", $vars)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+}
+
+sub changeEmail {
+
+ # Get the user's ID from the tokens table.
+ SendSQL("SELECT userid, eventdata FROM tokens
+ WHERE token = $::quotedtoken");
+ my ($userid, $eventdata) = FetchSQLData();
+ my ($old_email, $new_email) = split(/:/,$eventdata);
+ my $quotednewemail = SqlQuote($new_email);
+
+ # Check the user entered the correct old email address
+ if($::FORM{'email'} ne $old_email) {
+ DisplayError("Email Address confirmation failed");
+ exit;
+ }
+ # The new email address should be available as this was
+ # confirmed initially so cancel token if it is not still available
+ if (! ValidateNewUser($new_email,$old_email)) {
+ DisplayError("Account $new_email already exists.");
+ Token::Cancel($::token,"Account $new_email already exists.");
+ exit;
+ }
+
+ # Update the user's login name in the profiles table and delete the token
+ # from the tokens table.
+ SendSQL("LOCK TABLES profiles WRITE , tokens WRITE");
+ SendSQL("UPDATE profiles
+ SET login_name = $quotednewemail
+ WHERE userid = $userid");
+ SendSQL("DELETE FROM tokens WHERE token = $::quotedtoken");
+ SendSQL("DELETE FROM tokens WHERE userid = $userid
+ AND tokentype = 'emailnew'");
+ SendSQL("UNLOCK TABLES");
+
+ # Return HTTP response headers.
+ print "Content-Type: text/html\n\n";
+
+ # Let the user know their email address has been changed.
+
+ $vars->{'title'} = "Bugzilla Login Changed";
+ $vars->{'message'} = "Your Bugzilla login has been changed.";
+
+ $template->process("global/message.html.tmpl", $vars)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+}
+
+sub cancelChangeEmail {
+ # Get the user's ID from the tokens table.
+ SendSQL("SELECT userid, tokentype, eventdata FROM tokens
+ WHERE token = $::quotedtoken");
+ my ($userid, $tokentype, $eventdata) = FetchSQLData();
+ my ($old_email, $new_email) = split(/:/,$eventdata);
+
+ if($tokentype eq "emailold") {
+ $vars->{'message'} = "The request to change the email address " .
+ "for your account to $new_email has been cancelled.";
+
+ SendSQL("SELECT login_name FROM profiles WHERE userid = $userid");
+ my $actualemail = FetchSQLData();
+
+ # check to see if it has been altered
+ if($actualemail ne $old_email) {
+ my $quotedoldemail = SqlQuote($old_email);
+
+ SendSQL("LOCK TABLES profiles WRITE");
+ SendSQL("UPDATE profiles
+ SET login_name = $quotedoldemail
+ WHERE userid = $userid");
+ SendSQL("UNLOCK TABLES");
+ $vars->{'message'} .=
+ " Your old account settings have been reinstated.";
+ }
+ }
+ else {
+ $vars->{'message'} = "The request to change the email address " .
+ "for the $old_email account to $new_email has been cancelled.";
+ }
+ Token::Cancel($::token, $vars->{'message'});
+
+ SendSQL("LOCK TABLES tokens WRITE");
+ SendSQL("DELETE FROM tokens
+ WHERE userid = $userid
+ AND tokentype = 'emailold' OR tokentype = 'emailnew'");
+ SendSQL("UNLOCK TABLES");
+ # Return HTTP response headers.
+ print "Content-Type: text/html\n\n";
+ $vars->{'title'} = "Cancel Request to Change Email Address";
+
+ $template->process("global/message.html.tmpl", $vars)
+ || &::DisplayError("Template process failed: " . $template->error())
+ && exit;
+}
diff --git a/userprefs.cgi b/userprefs.cgi
index e38cd4095..ddeb0f1f7 100755
--- a/userprefs.cgi
+++ b/userprefs.cgi
@@ -65,16 +65,33 @@ chop $defaultflagstring;
sub DoAccount {
SendSQL("SELECT realname FROM profiles WHERE userid = $userid");
$vars->{'realname'} = FetchSQLData();
+
+ if(Param('allowemailchange')) {
+ SendSQL("SELECT tokentype, issuedate + INTERVAL 3 DAY, eventdata
+ FROM tokens
+ WHERE userid = $userid
+ AND tokentype LIKE 'email%'
+ ORDER BY tokentype ASC LIMIT 1");
+ if(MoreSQLData()) {
+ my ($tokentype, $change_date, $eventdata) = &::FetchSQLData();
+ $vars->{'login_change_date'} = $change_date;
+
+ if($tokentype eq 'emailnew') {
+ my ($oldemail,$newemail) = split(/:/,$eventdata);
+ $vars->{'new_login_name'} = $newemail;
+ }
+ }
+ }
}
sub SaveAccount {
+ my $pwd1 = $::FORM{'new_password1'};
+ my $pwd2 = $::FORM{'new_password2'};
+
if ($::FORM{'Bugzilla_password'} ne "" ||
- $::FORM{'new_password1'} ne "" ||
- $::FORM{'new_password2'} ne "")
+ $pwd1 ne "" || $pwd2 ne "")
{
my $old = SqlQuote($::FORM{'Bugzilla_password'});
- my $pwd1 = SqlQuote($::FORM{'new_password1'});
- my $pwd2 = SqlQuote($::FORM{'new_password2'});
SendSQL("SELECT cryptpassword FROM profiles WHERE userid = $userid");
my $oldcryptedpwd = FetchOneColumn();
if (!$oldcryptedpwd) {
@@ -87,23 +104,63 @@ sub SaveAccount {
DisplayError("You did not enter your old password correctly.");
exit;
}
- if ($pwd1 ne $pwd2) {
- DisplayError("The two passwords you entered did not match.");
- exit;
+
+ if ($pwd1 ne "" || $pwd2 ne "")
+ {
+ if ($pwd1 ne $pwd2) {
+ DisplayError("The two passwords you entered did not match.");
+ exit;
+ }
+ if ($::FORM{'new_password1'} eq '') {
+ DisplayError("You must enter a new password.");
+ exit;
+ }
+ my $passworderror = ValidatePassword($pwd1);
+ (DisplayError($passworderror) && exit) if $passworderror;
+
+ my $cryptedpassword = SqlQuote(Crypt($pwd1));
+ SendSQL("UPDATE profiles
+ SET cryptpassword = $cryptedpassword
+ WHERE userid = $userid");
+ # Invalidate all logins except for the current one
+ InvalidateLogins($userid, $::COOKIE{"Bugzilla_logincookie"});
}
- if ($::FORM{'new_password1'} eq '') {
- DisplayError("You must enter a new password.");
- exit;
+ }
+
+ if(Param("allowemailchange") && $::FORM{'new_login_name'}) {
+ my $old_login_name = $::FORM{'Bugzilla_login'};
+ my $new_login_name = trim($::FORM{'new_login_name'});
+
+ if($old_login_name ne $new_login_name) {
+ if( $::FORM{'Bugzilla_password'} eq "") {
+ DisplayError("You must enter your old password to
+ change email address.");
+ exit;
+ }
+
+ use Token;
+ # Block multiple email changes for the same user.
+ if (Token::HasEmailChangeToken($userid)) {
+ DisplayError("Email change already in progress;
+ please check your email.");
+ exit;
+ }
+
+ # Before changing an email address, confirm one does not exist.
+ CheckEmailSyntax($new_login_name);
+ trick_taint($new_login_name);
+ if (!ValidateNewUser($new_login_name)) {
+ DisplayError("Account $new_login_name already exists");
+ exit;
+ }
+
+ Token::IssueEmailChangeToken($userid,$old_login_name,
+ $new_login_name);
+
+ $vars->{'changes_saved'} =
+ "An email has been sent to both old and new email
+ addresses to confirm the change of email address.";
}
- my $passworderror = ValidatePassword($::FORM{'new_password1'});
- (DisplayError($passworderror) && exit) if $passworderror;
-
- my $cryptedpassword = SqlQuote(Crypt($::FORM{'new_password1'}));
- SendSQL("UPDATE profiles
- SET cryptpassword = $cryptedpassword
- WHERE userid = $userid");
- # Invalidate all logins except for the current one
- InvalidateLogins($userid, $::COOKIE{"Bugzilla_logincookie"});
}
SendSQL("UPDATE profiles SET " .