summaryrefslogtreecommitdiffstats
path: root/globals.pl
diff options
context:
space:
mode:
authorjustdave%syndicomm.com <>2001-07-11 14:29:16 +0200
committerjustdave%syndicomm.com <>2001-07-11 14:29:16 +0200
commit022265211b1a3b3dad3fcf679756392c3eb6a285 (patch)
tree79c99d0bea86b527395b4aac32a37eef739c67dc /globals.pl
parentf208e298e2ac9836c8138449a0691f6deb850c4a (diff)
downloadbugzilla-022265211b1a3b3dad3fcf679756392c3eb6a285.tar.gz
bugzilla-022265211b1a3b3dad3fcf679756392c3eb6a285.tar.xz
Fix for bug 77473, bug 74032, and bug 85472: Passwords are no longer stored in plaintext in the database. Passwords are no longer encrypted with MySQL's ENCRYPT() function (because it doesn't work on some installs), but with Perl's crypt() function. The crypt-related routines now properly deal with salts so that they work on systems that use methods other than UNIX crypt to crypt the passwords (such as MD5). Checksetup.pl will walk through your database and re-crypt everyone's passwords based on the plaintext password entry, then drop the plaintext password column. As a consequence of no longer having a plaintext password, it is no longer possible to email someone their password, so the login screen has been changed to request a password reset instead. The user is emailed a temporary identifying token, with a link back to Bugzilla. They click on the link or paste it into their browser and Bugzilla allows them to change their password.
Patch by Myk Melez <myk@mozilla.org> r= justdave@syndicomm.com, jake@acutex.net
Diffstat (limited to 'globals.pl')
-rw-r--r--globals.pl109
1 files changed, 100 insertions, 9 deletions
diff --git a/globals.pl b/globals.pl
index 736cb431a..302d9b8b7 100644
--- a/globals.pl
+++ b/globals.pl
@@ -616,19 +616,21 @@ sub GetVersionTable {
sub InsertNewUser {
my ($username, $realname) = (@_);
- my $password = "";
- for (my $i=0 ; $i<8 ; $i++) {
- $password .= substr("abcdefghijklmnopqrstuvwxyz", int(rand(26)), 1);
- }
+ # Generate a new random password for the user.
+ my $password = GenerateRandomPassword();
+ my $cryptpassword = Crypt($password);
+
+ # Determine what groups the user should be in by default
+ # and add them to those groups.
PushGlobalSQLState();
SendSQL("select bit, userregexp from groups where userregexp != ''");
my $groupset = "0";
while (MoreSQLData()) {
my @row = FetchSQLData();
- # Modified -Joe Robins, 2/17/00
- # Making this case insensitive, since usernames are email addresses,
- # and could be any case.
+ # Modified -Joe Robins, 2/17/00
+ # Making this case insensitive, since usernames are email addresses,
+ # and could be any case.
if ($username =~ m/$row[1]/i) {
$groupset .= "+ $row[0]"; # Silly hack to let MySQL do the math,
# not Perl, since we're dealing with 64
@@ -636,14 +638,103 @@ sub InsertNewUser {
# does that.
}
}
-
+
+ # Insert the new user record into the database.
$username = SqlQuote($username);
$realname = SqlQuote($realname);
- SendSQL("insert into profiles (login_name, realname, password, cryptpassword, groupset) values ($username, $realname, '$password', encrypt('$password'), $groupset)");
+ $cryptpassword = SqlQuote($cryptpassword);
+ SendSQL("INSERT INTO profiles (login_name, realname, cryptpassword, groupset)
+ VALUES ($username, $realname, $cryptpassword, $groupset)");
PopGlobalSQLState();
+
+ # Return the password to the calling code so it can be included
+ # in an email sent to the user.
+ return $password;
+}
+
+sub GenerateRandomPassword {
+ my ($size) = @_;
+
+ # Generated passwords are eight characters long by default.
+ $size ||= 8;
+
+ # The list of characters that can appear in a password.
+ # If you change this you must also update &ValidatePassword below.
+ my @pwchars = (0..9, 'A'..'Z', 'a'..'z', '-', '_');
+ #my @pwchars = (0..9, 'A'..'Z', 'a'..'z', '-', '_', '!', '@', '#', '$', '%', '^', '&', '*');
+
+ # The number of characters in the list.
+ my $pwcharslen = scalar(@pwchars);
+
+ # Generate the password.
+ my $password = "";
+ for ( my $i=0 ; $i<$size ; $i++ ) {
+ $password .= $pwchars[rand($pwcharslen)];
+ }
+
+ # Return the password.
return $password;
}
+
+sub ValidatePassword {
+ # Determines whether or not a password is valid (i.e. meets Bugzilla's
+ # requirements for length and content). If the password is valid, the
+ # function returns boolean false. Otherwise it returns an error message
+ # (synonymous with boolean true) that can be displayed to the user.
+
+ # If a second password is passed in, this function also verifies that
+ # the two passwords match.
+
+ my ($password, $matchpassword) = @_;
+
+ if ( $password !~ /^[a-zA-Z0-9-_]*$/ ) {
+ return "The password contains an illegal character. Legal characters are letters, numbers, hyphens (-), and underlines (_).";
+ } elsif ( length($password) < 3 ) {
+ return "The password is less than three characters long. It must be at least three characters.";
+ } elsif ( length($password) > 16 ) {
+ return "The password is more than 16 characters long. It must be no more than 16 characters.";
+ } elsif ( $matchpassword && $password ne $matchpassword ) {
+ return "The two passwords do not match.";
+ }
+
+ return 0;
+}
+
+
+sub Crypt {
+ # Crypts a password, generating a random salt to do it.
+ # Random salts are generated because the alternative is usually
+ # to use the first two characters of the password itself, and since
+ # the salt appears in plaintext at the beginning of the crypted
+ # password string this has the effect of revealing the first two
+ # characters of the password to anyone who views the crypted version.
+
+ my ($password) = @_;
+
+ # The list of characters that can appear in a salt. Salts and hashes
+ # are both encoded as a sequence of characters from a set containing
+ # 64 characters, each one of which represents 6 bits of the salt/hash.
+ # The encoding is similar to BASE64, the difference being that the
+ # BASE64 plus sign (+) is replaced with a forward slash (/).
+ my @saltchars = (0..9, 'A'..'Z', 'a'..'z', '.', '/');
+
+ # Generate the salt. We use an 8 character (48 bit) salt for maximum
+ # security on systems whose crypt uses MD5. Systems with older
+ # versions of crypt will just use the first two characters of the salt.
+ my $salt = '';
+ for ( my $i=0 ; $i < 8 ; ++$i ) {
+ $salt .= $saltchars[rand(64)];
+ }
+
+ # Crypt the password.
+ my $cryptedpassword = crypt($password, $salt);
+
+ # Return the crypted password.
+ return $cryptedpassword;
+}
+
+
sub DBID_to_real_or_loginname {
my ($id) = (@_);
PushGlobalSQLState();