]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 285695: [PostgreSQL] Username checks for login, etc. need to be case insensitive
authormkanat%kerio.com <>
Fri, 8 Jul 2005 09:31:41 +0000 (09:31 +0000)
committermkanat%kerio.com <>
Fri, 8 Jul 2005 09:31:41 +0000 (09:31 +0000)
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> r=LpSolit, a=justdave

14 files changed:
Bugzilla/Auth/Login/WWW/Env.pm
Bugzilla/Auth/Verify/DB.pm
Bugzilla/Auth/Verify/LDAP.pm
Bugzilla/DB.pm
Bugzilla/DB/Mysql.pm
Bugzilla/Token.pm
Bugzilla/User.pm
checksetup.pl
contrib/BugzillaEmail.pm
contrib/bug_email.pl
contrib/bugzilla_email_append.pl
contrib/syncLDAP.pl
request.cgi
token.cgi

index 2f29d570fdba374217e45b98ce04f3b06360dd8f..9853932065f21e60432d467f29e9d3e5ecacb3cc 100644 (file)
@@ -84,7 +84,8 @@ sub login {
             # also sent), and the id, so that we have a way of telling that we
             # got something instead of a bunch of NULLs
             $sth = $dbh->prepare("SELECT extern_id, userid, disabledtext " .
-                                 "FROM profiles WHERE login_name=?");
+                                 "FROM profiles WHERE " .
+                                 $dbh->sql_istrcmp('login_name', '?'));
             $sth->execute($env_email);
 
             $sth->execute();
index 1d5c6850cdcd30895d7a749eee3be0da6ac50450..4a45e81e7d7c7ccd24f5b780606f2b302d84eae7 100644 (file)
@@ -34,6 +34,10 @@ use strict;
 use Bugzilla::Config;
 use Bugzilla::Constants;
 use Bugzilla::Util;
+# Because of the screwy way that Auth works, it thinks
+# that we're redefining subroutines if we "use" anything
+# that "uses" Bugzilla::Auth.
+require Bugzilla::User;
 
 my $edit_options = {
     'new' => 1,
@@ -52,11 +56,8 @@ sub authenticate {
 
     return (AUTH_NODATA) unless defined $username && defined $passwd;
 
-    # We're just testing against the db: any value is ok
-    trick_taint($username);
-
-    my $userid = $class->get_id_from_username($username);
-    return (AUTH_LOGINFAILED) unless defined $userid;
+    my $userid = Bugzilla::User::login_to_id($username);
+    return (AUTH_LOGINFAILED) unless $userid;
 
     return (AUTH_LOGINFAILED, $userid) 
         unless $class->check_password($userid, $passwd);
@@ -74,15 +75,6 @@ sub authenticate {
     return (AUTH_OK, $userid);
 }
 
-sub get_id_from_username {
-    my ($class, $username) = @_;
-    my $dbh = Bugzilla->dbh;
-    my $sth = $dbh->prepare_cached("SELECT userid FROM profiles " .
-                                   "WHERE login_name=?");
-    my ($userid) = $dbh->selectrow_array($sth, undef, $username);
-    return $userid;
-}
-
 sub get_disabled {
     my ($class, $userid) = @_;
     my $dbh = Bugzilla->dbh;
index 551a70f45b55b1328f224a61c45df314dd73e507..ee58f9d7e5660bab16b9f63941d8165b92a69956 100644 (file)
@@ -137,7 +137,8 @@ sub authenticate {
     my $dbh = Bugzilla->dbh;
     my $sth = $dbh->prepare_cached("SELECT userid, disabledtext " .
                                    "FROM profiles " .
-                                   "WHERE login_name=?");
+                                   "WHERE " .
+                                   $dbh->sql_istrcmp('login_name', '?'));
     my ($userid, $disabledtext) =
       $dbh->selectrow_array($sth,
                             undef,
index e11d5259293eefe4280be76b5e8753aa851c1b13..76e090d6ca55a1f7ee9af9c2f8bb11236128f6ec 100644 (file)
@@ -218,6 +218,19 @@ sub import {
     $Exporter::ExportLevel-- if $is_exporter;
 }
 
+sub sql_istrcmp {
+    my ($self, $left, $right, $op) = @_;
+    $op ||= "=";
+
+    return $self->sql_istring($left) . " $op " . $self->sql_istring($right);
+}
+
+sub sql_istring {
+    my ($self, $string) = @_;
+
+    return "LOWER($string)";
+}
+
 sub sql_position {
     my ($self, $fragment, $text) = @_;
 
@@ -1153,6 +1166,33 @@ formatted SQL command have prefix C<sql_>. All other methods have prefix C<bz_>.
               $text = text to search for (scalar)
  Returns:     formatted SQL for for full text search
 
+=item C<sql_istrcmp>
+
+ Description: Returns SQL for a case-insensitive string comparison.
+ Params:      $left - What should be on the left-hand-side of the
+                      operation.
+              $right - What should be on the right-hand-side of the
+                       operation.
+              $op (optional) - What the operation is. Should be a 
+                  valid ANSI SQL comparison operator, like "=", "<", 
+                  "LIKE", etc. Defaults to "=" if not specified.
+ Returns:     A SQL statement that will run the comparison in 
+              a case-insensitive fashion.
+ Note:        Uses sql_istring, so it has the same performance concerns.
+              Try to avoid using this function unless absolutely necessary.
+              Subclass Implementors: Override sql_istring instead of this
+              function, most of the time (this function uses sql_istring).
+
+=item C<sql_istring>
+
+ Description: Returns SQL syntax "preparing" a string or text column for
+              case-insensitive comparison. 
+ Params:      $string - string to convert (scalar)
+ Returns:     formatted SQL making the string case insensitive
+ Note:        The default implementation simply calls LOWER on the parameter.
+              If this is used to search on a text column with index, the index
+              will not be usually used unless it was created as LOWER(column).
+
 =item C<bz_lock_tables>
 
  Description: Performs a table lock operation on specified tables.
index 3472a351d25a6ab140d875ef0096987361855d50..983cb3b06acad20c0cdca46fd16973bd2ab761bb 100644 (file)
@@ -111,6 +111,12 @@ sub sql_fulltext_search {
     return "MATCH($column) AGAINST($text)";
 }
 
+sub sql_istring {
+    my ($self, $string) = @_;
+    
+    return $string;
+}
+
 sub sql_to_days {
     my ($self, $date) = @_;
 
index 2262e3e7330f5825dbb1c4965f3d4b35bb4dfaf9..fe72915a36b4a725d2f0599b50fc5d7853f87e03 100644 (file)
@@ -104,7 +104,7 @@ sub IssuePasswordToken {
                     AND tokens.tokentype = 'password'
                     AND tokens.issuedate > NOW() - " .
                     $dbh->sql_interval('10 MINUTE') . "
-                    WHERE login_name = $quotedloginname");
+                 WHERE " . $dbh->sql_istrcmp('login_name', $quotedloginname));
     my ($userid, $toosoon) = &::FetchSQLData();
 
     if ($toosoon) {
index ff3d38721545f1e60b4b3a9fb13b55605293af66..0c2de0f4c1b8883cba1b8e16c67754f11c157f36 100644 (file)
@@ -84,7 +84,8 @@ sub new {
 # in the id its already had to validate (or the User.pm object, of course)
 sub new_from_login {
     my $invocant = shift;
-    return $invocant->_create("login_name=?", @_);
+    my $dbh = Bugzilla->dbh;
+    return $invocant->_create($dbh->sql_istrcmp('login_name', '?'), @_);
 }
 
 # Internal helper for the above |new| methods
@@ -631,14 +632,15 @@ sub match {
 
         # Build the query.
         my $sqlstr = &::SqlQuote($wildstr);
-        my $query  = "SELECT DISTINCT userid, realname, login_name, " .\r
+        my $query  = "SELECT DISTINCT userid, realname, login_name, " .
                      "LENGTH(login_name) AS namelength " .
                      "FROM profiles ";
         if (&::Param('usevisibilitygroups')) {
             $query .= ", user_group_map ";
         }
-        $query    .= "WHERE (login_name LIKE $sqlstr " .
-                     "OR realname LIKE $sqlstr) ";
+        $query .= "WHERE ("  
+            . $dbh->sql_istrcmp('login_name', $sqlstr, "LIKE") . " OR " .
+              $dbh->sql_istrcmp('realname', $sqlstr, "LIKE") . ") ";
         if (&::Param('usevisibilitygroups')) {
             $query .= "AND user_group_map.user_id = userid " .
                       "AND isbless = 0 " .
@@ -664,7 +666,7 @@ sub match {
         my $sqlstr = &::SqlQuote($str);
         my $query  = "SELECT userid, realname, login_name " .
                      "FROM profiles " .
-                     "WHERE login_name = $sqlstr ";
+                     "WHERE " . $dbh->sql_istrcmp('login_name', $sqlstr);
         # Exact matches don't care if a user is disabled.
 
         &::PushGlobalSQLState();
@@ -1213,8 +1215,9 @@ sub login_to_id ($) {
     my $dbh = Bugzilla->dbh;
     # $login will only be used by the following SELECT statement, so it's safe.
     trick_taint($login);
-    my $user_id = $dbh->selectrow_array(
-        "SELECT userid FROM profiles WHERE login_name = ?", undef, $login);
+    my $user_id = $dbh->selectrow_array("SELECT userid FROM profiles WHERE " .
+                                        $dbh->sql_istrcmp('login_name', '?'),
+                                        undef, $login);
     if ($user_id) {
         return $user_id;
     } else {
index cd991d5617e828e64287fb7ee7347713c9f1b41b..42582fa65530d5eb55d3869cd87a7d6495cae303 100755 (executable)
@@ -4155,7 +4155,7 @@ if ($sth->rows == 0) {
             }
         }
         $sth = $dbh->prepare("SELECT login_name FROM profiles " .
-                              "WHERE login_name = ?");
+                              "WHERE " . $dbh->sql_istrcmp('login_name', '?'));
         $sth->execute($login);
         if ($sth->rows > 0) {
             print "$login already has an account.\n";
@@ -4258,9 +4258,10 @@ if ($sth->rows == 0) {
     }
 
     # Put the admin in each group if not already    
-    my $userid = $dbh->selectrow_array(
-        "SELECT userid FROM profiles WHERE login_name = ?", undef, $login); 
-   
+    my $userid = $dbh->selectrow_array("SELECT userid FROM profiles WHERE " .
+                                       $dbh->sql_istrcmp('login_name', '?'),
+                                       undef, $login);
+
     # Admins get explicit membership and bless capability for the admin group
     my ($admingroupid) = $dbh->selectrow_array("SELECT id FROM groups 
                                                 WHERE name = 'admin'");
index 48602cdb71bd6fe1846632c0a4d64d7ba0efa69c..473169c9e59403ac249145b0cf3a9c7b7094c9af 100644 (file)
@@ -31,6 +31,8 @@ require "globals.pl";
 
 use strict;
 
+my $dbh = Bugzilla->dbh;
+
 my $EMAIL_TRANSFORM_NONE = "email_transform_none";
 my $EMAIL_TRANSFORM_BASE_DOMAIN = "email_transform_base_domain";
 my $EMAIL_TRANSFORM_NAME_ONLY = "email_transform_name_only";
@@ -45,13 +47,15 @@ sub findUser($) {
   my ($address) = @_;
   # if $email_transform is $EMAIL_TRANSFORM_NONE, return the address, otherwise, return undef
   if ($email_transform eq $EMAIL_TRANSFORM_NONE) {
-    my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name = \'$address\';";
+    my $stmt = "SELECT login_name FROM profiles WHERE " .
+               $dbh->sql_istrcmp('login_name', $dbh->quote($address));
     SendSQL($stmt);
     my $found_address = FetchOneColumn();
     return $found_address;
   } elsif ($email_transform eq $EMAIL_TRANSFORM_BASE_DOMAIN) {
     my ($username) = ($address =~ /(.+)@/);
-    my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name RLIKE \'$username\';";
+    my $stmt = "SELECT login_name FROM profiles WHERE " . $dbh->sql_istrcmp(
+               'login_name', $dbh->quote($username), $dbh->sql_regexp());
     SendSQL($stmt);
 
     my $domain;
@@ -68,7 +72,8 @@ sub findUser($) {
     return $new_address;
   } elsif ($email_transform eq $EMAIL_TRANSFORM_NAME_ONLY) {
     my ($username) = ($address =~ /(.+)@/);
-    my $stmt = "SELECT login_name FROM profiles WHERE profiles.login_name RLIKE \'$username\';";
+    my $stmt = "SELECT login_name FROM profiles WHERE " .$dbh->sql_istrcmp(
+                'login_name', $dbh->quote($username), $dbh->sql_regexp());
     SendSQL($stmt);
     my $found_address = FetchOneColumn();
     return $found_address;
index 46c23c3c37cc07318ab0814dc15b8be0552cea74..1590387e65da8a7b7b9e2c7bf7734483b1970442 100755 (executable)
@@ -38,7 +38,7 @@
 #
 # You need to work with bug_email.pl the MIME::Parser installed.
 # 
-# $Id: bug_email.pl,v 1.27 2005/05/12 19:13:56 lpsolit%gmail.com Exp $
+# $Id: bug_email.pl,v 1.28 2005/07/08 02:31:43 mkanat%kerio.com Exp $
 ###############################################################
 
 # 02/12/2000 (SML)
@@ -112,6 +112,8 @@ my $restricted = 0;
 my $SenderShort;
 my $Message_ID;
 
+my $dbh = Bugzilla->dbh;
+
 # change to use default product / component functionality
 my $DEFAULT_PRODUCT = "PENDING";
 my $DEFAULT_COMPONENT = "PENDING";
@@ -1149,7 +1151,8 @@ END
     $query .=  $state . ", \'$bug_when\', \'$bug_when\', $ever_confirmed)\n";
 #    $query .=  SqlQuote( "NEW" ) . ", now(), " . SqlQuote($comment) . " )\n";
 
-    SendSQL("SELECT userid FROM profiles WHERE login_name=\'$reporter\'");
+    SendSQL("SELECT userid FROM profiles WHERE " .
+            $dbh->sql_istrcmp('login_name', $dbh->quote($reporter)));
     my $userid = FetchOneColumn();
 
     my $id;
index fee9b62ac8b67da3602e753f03217c01135fecb6..e409f08628ed99e08c32550640e83363c009e7da 100755 (executable)
@@ -42,6 +42,8 @@ use BugzillaEmail;
 use Bugzilla::Config qw(:DEFAULT $datadir);
 use Bugzilla::BugMail;
 
+my $dbh = Bugzilla->dbh;
+
 # Create a new MIME parser:
 my $parser = new MIME::Parser;
 
@@ -101,7 +103,8 @@ if (!defined($found_id)) {
 }
 
 # get the user id
-SendSQL("SELECT userid FROM profiles WHERE login_name = \'$SenderShort\';");
+SendSQL("SELECT userid FROM profiles WHERE " . 
+        $dbh->sql_istrcmp('login_name', $dbh->quote($SenderShort)));
 my $userid = FetchOneColumn();
 if (!defined($userid)) {
   DealWithError("Userid not found for $SenderShort");
index b9d3e8a5fa2da1b7db0b671ae34bcb2b764fdd59..14ba1402cea023d6bf019867b52540e637bdb7b0 100755 (executable)
@@ -30,6 +30,7 @@ use lib qw(.);
 use Net::LDAP;
 
 my $cgi = Bugzilla->cgi;
+my $dbh = Bugzilla->dbh;
 
 my $readonly = 0;
 my $nodisable = 0;
@@ -237,7 +238,9 @@ if($readonly == 0) {
    print "Performing DB update:\nPhase 1: disabling not-existing users... " unless $quiet;
    if($nodisable == 0) {
       while( my ($key, $value) = each(%disable_users) ) {
-        SendSQL("UPDATE profiles SET disabledtext = 'auto-disabled by ldap sync' WHERE login_name='$key'" );
+        SendSQL("UPDATE profiles SET disabledtext = 'auto-disabled by ldap " .
+                "sync' WHERE " . $dbh->sql_istrcmp('login_name', 
+                $dbh->quote($key)));
       }
       print "done!\n" unless $quiet;
    }
@@ -249,9 +252,12 @@ if($readonly == 0) {
    if($noupdate == 0) {
       while( my ($key, $value) = each(%update_users) ) {
         if(defined @$value{'new_login_name'}) {
-          SendSQL("UPDATE profiles SET login_name = '" . @$value{'new_login_name'} . "' WHERE login_name='$key'" );
+          SendSQL("UPDATE profiles SET login_name = '" . 
+                  @$value{'new_login_name'} . "' WHERE " .
+                  $dbh->sql_istrcmp('login_name', $dbh->quote($key)));
         } else {
-          SendSQL("UPDATE profiles SET realname = '" . @$value{'realname'} . "' WHERE login_name='$key'" );
+          SendSQL("UPDATE profiles SET realname = '" . @$value{'realname'} .
+                   "' WHERE " . $dbh->sql_istrcmp('login_name', $dbh->quote($key)));
         }
       }
       print "done!\n" unless $quiet;
index bc5eefa9acd83c962be955e8163f050fdb2972f7..4c6e7600f227b56ce88c1a136bb0bf5d2733226b 100755 (executable)
@@ -145,12 +145,14 @@ sub queue {
     
     # Filter results by exact email address of requester or requestee.
     if (defined $cgi->param('requester') && $cgi->param('requester') ne "") {
-        push(@criteria, "requesters.login_name = " . SqlQuote($cgi->param('requester')));
+        push(@criteria, $dbh->sql_istrcmp('requesters.login_name',
+                                          SqlQuote($cgi->param('requester'))));
         push(@excluded_columns, 'requester') unless $cgi->param('do_union');
     }
     if (defined $cgi->param('requestee') && $cgi->param('requestee') ne "") {
         if ($cgi->param('requestee') ne "-") {
-            push(@criteria, "requestees.login_name = " . SqlQuote($cgi->param('requestee')));
+            push(@criteria, $dbh->sql_istrcmp('requestees.login_name',
+                            SqlQuote($cgi->param('requestee'))));
         }
         else { push(@criteria, "flags.requestee_id IS NULL") }
         push(@excluded_columns, 'requestee') unless $cgi->param('do_union');
index d8c3fe2888f0a295f37243b6b61f301fe3548aa7..64bf8e364d8e70b1082d4667538e754eb570eb53 100755 (executable)
--- a/token.cgi
+++ b/token.cgi
@@ -36,6 +36,7 @@ use Bugzilla::Constants;
 use Bugzilla::Auth;
 
 my $cgi = Bugzilla->cgi;
+my $dbh = Bugzilla->dbh;
 
 # Include the Bugzilla CGI and general utility library.
 require "CGI.pl";
@@ -114,7 +115,8 @@ if ( $::action eq 'reqpw' ) {
     CheckEmailSyntax($cgi->param('loginname'));
 
     my $quotedloginname = SqlQuote($cgi->param('loginname'));
-    SendSQL("SELECT userid FROM profiles WHERE login_name = $quotedloginname");
+    SendSQL("SELECT userid FROM profiles WHERE " .
+            $dbh->sql_istrcmp('login_name', $quotedloginname));
     FetchSQLData()
       || ThrowUserError("account_inexistent");
 }